t_siginfo.c revision 313498
1/* $NetBSD: t_siginfo.c,v 1.30 2015/12/22 14:25:58 christos Exp $ */
2
3/*-
4 * Copyright (c) 2010 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <atf-c.h>
30
31#ifdef __NetBSD__
32#include <sys/inttypes.h>
33#endif
34#include <sys/resource.h>
35#include <sys/sysctl.h>
36#include <sys/time.h>
37#include <sys/ucontext.h>
38#include <sys/wait.h>
39
40#include <assert.h>
41#include <signal.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45#include <unistd.h>
46#include <setjmp.h>
47#include <float.h>
48
49#include <fenv.h>
50#ifdef __HAVE_FENV
51#include <ieeefp.h>	/* only need for ARM Cortex/Neon hack */
52#elif defined(_FLOAT_IEEE754)
53#include <ieeefp.h>
54#endif
55
56#include "isqemu.h"
57
58/* for sigbus */
59volatile char *addr;
60
61/* for sigchild */
62pid_t child;
63int code;
64int status;
65
66/* for sigfpe */
67sig_atomic_t fltdiv_signalled = 0;
68sig_atomic_t intdiv_signalled = 0;
69
70static void
71sig_debug(int signo, siginfo_t *info, ucontext_t *ctx)
72{
73	unsigned int i;
74
75	printf("%d %p %p\n", signo, info, ctx);
76	if (info != NULL) {
77		printf("si_signo=%d\n", info->si_signo);
78		printf("si_errno=%d\n", info->si_errno);
79		printf("si_code=%d\n", info->si_code);
80		printf("si_value.sival_int=%d\n", info->si_value.sival_int);
81	}
82	if (ctx != NULL) {
83		printf("uc_flags 0x%x\n", ctx->uc_flags);
84		printf("uc_link %p\n", ctx->uc_link);
85		for (i = 0; i < __arraycount(ctx->uc_sigmask.__bits); i++)
86			printf("uc_sigmask[%d] 0x%x\n", i,
87			    ctx->uc_sigmask.__bits[i]);
88		printf("uc_stack %p %lu 0x%x\n", ctx->uc_stack.ss_sp,
89		    (unsigned long)ctx->uc_stack.ss_size,
90		    ctx->uc_stack.ss_flags);
91#ifdef __NetBSD__
92		for (i = 0; i < __arraycount(ctx->uc_mcontext.__gregs); i++)
93			printf("uc_mcontext.greg[%d] 0x%lx\n", i,
94			    (long)ctx->uc_mcontext.__gregs[i]);
95#endif
96	}
97}
98
99static void
100sigalrm_action(int signo, siginfo_t *info, void *ptr)
101{
102
103	sig_debug(signo, info, (ucontext_t *)ptr);
104
105	ATF_REQUIRE_EQ(info->si_signo, SIGALRM);
106	ATF_REQUIRE_EQ(info->si_code, SI_TIMER);
107	ATF_REQUIRE_EQ(info->si_value.sival_int, ITIMER_REAL);
108
109	atf_tc_pass();
110	/* NOTREACHED */
111}
112
113ATF_TC(sigalarm);
114
115ATF_TC_HEAD(sigalarm, tc)
116{
117
118	atf_tc_set_md_var(tc, "descr",
119	    "Checks that signal trampoline correctly calls SIGALRM handler");
120}
121
122ATF_TC_BODY(sigalarm, tc)
123{
124	struct sigaction sa;
125	sa.sa_flags = SA_SIGINFO;
126	sa.sa_sigaction = sigalrm_action;
127	sigemptyset(&sa.sa_mask);
128	sigaction(SIGALRM, &sa, NULL);
129	for (;;) {
130		alarm(1);
131		sleep(1);
132	}
133	atf_tc_fail("SIGALRM handler wasn't called");
134}
135
136static void
137sigchild_action(int signo, siginfo_t *info, void *ptr)
138{
139	if (info != NULL) {
140		printf("info=%p\n", info);
141		printf("ptr=%p\n", ptr);
142		printf("si_signo=%d\n", info->si_signo);
143		printf("si_errno=%d\n", info->si_errno);
144		printf("si_code=%d\n", info->si_code);
145		printf("si_uid=%d\n", info->si_uid);
146		printf("si_pid=%d\n", info->si_pid);
147		printf("si_status=%d\n", info->si_status);
148#ifdef __NetBSD__
149		printf("si_utime=%lu\n", (unsigned long int)info->si_utime);
150		printf("si_stime=%lu\n", (unsigned long int)info->si_stime);
151#endif
152	}
153	ATF_REQUIRE_EQ(info->si_code, code);
154	ATF_REQUIRE_EQ(info->si_signo, SIGCHLD);
155	ATF_REQUIRE_EQ(info->si_uid, getuid());
156	ATF_REQUIRE_EQ(info->si_pid, child);
157	if (WIFEXITED(info->si_status))
158		ATF_REQUIRE_EQ(WEXITSTATUS(info->si_status), status);
159	else if (WIFSTOPPED(info->si_status))
160		ATF_REQUIRE_EQ(WSTOPSIG(info->si_status), status);
161	else if (WIFSIGNALED(info->si_status))
162		ATF_REQUIRE_EQ(WTERMSIG(info->si_status), status);
163}
164
165static void
166setchildhandler(void (*action)(int, siginfo_t *, void *))
167{
168	struct sigaction sa;
169	sa.sa_flags = SA_SIGINFO;
170	sa.sa_sigaction = action;
171	sigemptyset(&sa.sa_mask);
172	sigaction(SIGCHLD, &sa, NULL);
173}
174
175static void
176sigchild_setup(void)
177{
178	sigset_t set;
179	struct rlimit rlim;
180
181	(void)getrlimit(RLIMIT_CORE, &rlim);
182	rlim.rlim_cur = rlim.rlim_max;
183	(void)setrlimit(RLIMIT_CORE, &rlim);
184
185	setchildhandler(sigchild_action);
186	sigemptyset(&set);
187	sigaddset(&set, SIGCHLD);
188	sigprocmask(SIG_BLOCK, &set, NULL);
189}
190
191ATF_TC(sigchild_normal);
192ATF_TC_HEAD(sigchild_normal, tc)
193{
194
195	atf_tc_set_md_var(tc, "descr",
196	    "Checks that signal trampoline correctly calls SIGCHLD handler "
197	    "when child exits normally");
198}
199
200ATF_TC_BODY(sigchild_normal, tc)
201{
202	sigset_t set;
203
204	sigchild_setup();
205
206	status = 25;
207	code = CLD_EXITED;
208
209	switch ((child = fork())) {
210	case 0:
211		sleep(1);
212		exit(status);
213	case -1:
214		atf_tc_fail("fork failed");
215	default:
216		sigemptyset(&set);
217		sigsuspend(&set);
218	}
219}
220
221ATF_TC(sigchild_dump);
222ATF_TC_HEAD(sigchild_dump, tc)
223{
224
225	atf_tc_set_md_var(tc, "descr",
226	    "Checks that signal trampoline correctly calls SIGCHLD handler "
227	    "when child segfaults");
228}
229
230ATF_TC_BODY(sigchild_dump, tc)
231{
232	sigset_t set;
233
234	sigchild_setup();
235
236	status = SIGSEGV;
237	code = CLD_DUMPED;
238
239	switch ((child = fork())) {
240	case 0:
241		sleep(1);
242		*(volatile long *)0 = 0;
243		atf_tc_fail("Child did not segfault");
244		/* NOTREACHED */
245	case -1:
246		atf_tc_fail("fork failed");
247	default:
248		sigemptyset(&set);
249		sigsuspend(&set);
250	}
251}
252
253ATF_TC(sigchild_kill);
254ATF_TC_HEAD(sigchild_kill, tc)
255{
256
257	atf_tc_set_md_var(tc, "descr",
258	    "Checks that signal trampoline correctly calls SIGCHLD handler "
259	    "when child is killed");
260}
261
262ATF_TC_BODY(sigchild_kill, tc)
263{
264	sigset_t set;
265
266	sigchild_setup();
267
268	status = SIGPIPE;
269	code = CLD_KILLED;
270
271	switch ((child = fork())) {
272	case 0:
273		sigemptyset(&set);
274		sigsuspend(&set);
275		break;
276	case -1:
277		atf_tc_fail("fork failed");
278	default:
279		kill(child, SIGPIPE);
280		sigemptyset(&set);
281		sigsuspend(&set);
282	}
283}
284
285static sigjmp_buf sigfpe_flt_env;
286static void
287sigfpe_flt_action(int signo, siginfo_t *info, void *ptr)
288{
289
290	sig_debug(signo, info, (ucontext_t *)ptr);
291
292	if (fltdiv_signalled++ != 0)
293		atf_tc_fail("FPE handler called more than once");
294
295	ATF_REQUIRE_EQ(info->si_signo, SIGFPE);
296	ATF_REQUIRE_EQ(info->si_code, FPE_FLTDIV);
297	ATF_REQUIRE_EQ(info->si_errno, 0);
298
299	siglongjmp(sigfpe_flt_env, 1);
300}
301
302ATF_TC(sigfpe_flt);
303ATF_TC_HEAD(sigfpe_flt, tc)
304{
305
306	atf_tc_set_md_var(tc, "descr",
307	    "Checks that signal trampoline correctly calls SIGFPE handler "
308	    "for floating div-by-zero");
309}
310
311ATF_TC_BODY(sigfpe_flt, tc)
312{
313	struct sigaction sa;
314	double d = strtod("0", NULL);
315
316	if (isQEMU())
317		atf_tc_skip("Test does not run correctly under QEMU");
318#if defined(__powerpc__)
319	atf_tc_skip("Test not valid on powerpc");
320#elif defined(__arm__) && !__SOFTFP__
321	/*
322	 * Some NEON fpus do not implement IEEE exception handling,
323	 * skip these tests if running on them and compiled for
324	 * hard float.
325	 */
326	if (0 == fpsetmask(fpsetmask(FP_X_INV)))
327		atf_tc_skip("FPU does not implement exception handling");
328#endif
329	if (sigsetjmp(sigfpe_flt_env, 0) == 0) {
330		sa.sa_flags = SA_SIGINFO;
331		sa.sa_sigaction = sigfpe_flt_action;
332		sigemptyset(&sa.sa_mask);
333		sigaction(SIGFPE, &sa, NULL);
334#ifdef __HAVE_FENV
335		feenableexcept(FE_ALL_EXCEPT);
336#elif defined(_FLOAT_IEEE754)
337		fpsetmask(FP_X_INV|FP_X_DZ|FP_X_OFL|FP_X_UFL|FP_X_IMP);
338#endif
339		printf("%g\n", 1 / d);
340	}
341	if (fltdiv_signalled == 0)
342		atf_tc_fail("FPE signal handler was not invoked");
343}
344
345static sigjmp_buf sigfpe_int_env;
346static void
347sigfpe_int_action(int signo, siginfo_t *info, void *ptr)
348{
349
350	sig_debug(signo, info, (ucontext_t *)ptr);
351
352	if (intdiv_signalled++ != 0)
353		atf_tc_fail("INTDIV handler called more than once");
354
355	ATF_REQUIRE_EQ(info->si_signo, SIGFPE);
356	ATF_REQUIRE_EQ(info->si_code, FPE_INTDIV);
357	atf_tc_expect_pass();
358	ATF_REQUIRE_EQ(info->si_errno, 0);
359
360	siglongjmp(sigfpe_int_env, 1);
361}
362
363ATF_TC(sigfpe_int);
364ATF_TC_HEAD(sigfpe_int, tc)
365{
366
367	atf_tc_set_md_var(tc, "descr",
368	    "Checks that signal trampoline correctly calls SIGFPE handler "
369	    "for integer div-by-zero (PR port-i386/43655)");
370}
371
372ATF_TC_BODY(sigfpe_int, tc)
373{
374	struct sigaction sa;
375	long l = strtol("0", NULL, 10);
376
377#if defined(__powerpc__)
378	atf_tc_skip("Test not valid on powerpc");
379#endif
380	if (sigsetjmp(sigfpe_int_env, 0) == 0) {
381		sa.sa_flags = SA_SIGINFO;
382		sa.sa_sigaction = sigfpe_int_action;
383		sigemptyset(&sa.sa_mask);
384		sigaction(SIGFPE, &sa, NULL);
385#ifdef __HAVE_FENV
386		feenableexcept(FE_ALL_EXCEPT);
387#elif defined(_FLOAT_IEEE754)
388		fpsetmask(FP_X_INV|FP_X_DZ|FP_X_OFL|FP_X_UFL|FP_X_IMP);
389#endif
390		printf("%ld\n", 1 / l);
391	}
392	if (intdiv_signalled == 0)
393		atf_tc_fail("FPE signal handler was not invoked");
394}
395
396static void
397sigsegv_action(int signo, siginfo_t *info, void *ptr)
398{
399
400	sig_debug(signo, info, (ucontext_t *)ptr);
401
402	ATF_REQUIRE_EQ(info->si_signo, SIGSEGV);
403	ATF_REQUIRE_EQ(info->si_errno, 0);
404	ATF_REQUIRE_EQ(info->si_code, SEGV_MAPERR);
405	ATF_REQUIRE_EQ(info->si_addr, (void *)0);
406
407	atf_tc_pass();
408	/* NOTREACHED */
409}
410
411ATF_TC(sigsegv);
412ATF_TC_HEAD(sigsegv, tc)
413{
414
415	atf_tc_set_md_var(tc, "descr",
416	    "Checks that signal trampoline correctly calls SIGSEGV handler");
417}
418
419ATF_TC_BODY(sigsegv, tc)
420{
421	struct sigaction sa;
422
423	sa.sa_flags = SA_SIGINFO;
424	sa.sa_sigaction = sigsegv_action;
425	sigemptyset(&sa.sa_mask);
426	sigaction(SIGSEGV, &sa, NULL);
427
428	*(volatile long *)0 = 0;
429	atf_tc_fail("Test did not fault as expected");
430}
431
432static void
433sigbus_action(int signo, siginfo_t *info, void *ptr)
434{
435
436	printf("si_addr = %p\n", info->si_addr);
437	sig_debug(signo, info, (ucontext_t *)ptr);
438
439	ATF_REQUIRE_EQ(info->si_signo, SIGBUS);
440	ATF_REQUIRE_EQ(info->si_errno, 0);
441	ATF_REQUIRE_EQ(info->si_code, BUS_ADRALN);
442
443#if defined(__i386__) || defined(__x86_64__)
444	atf_tc_expect_fail("x86 architecture does not correctly "
445	    "report the address where the unaligned access occured");
446#endif
447	ATF_REQUIRE_EQ(info->si_addr, (volatile void *)addr);
448
449	atf_tc_pass();
450	/* NOTREACHED */
451}
452
453ATF_TC(sigbus_adraln);
454ATF_TC_HEAD(sigbus_adraln, tc)
455{
456
457	atf_tc_set_md_var(tc, "descr",
458	    "Checks that signal trampoline correctly calls SIGBUS handler "
459	    "for invalid address alignment");
460}
461
462ATF_TC_BODY(sigbus_adraln, tc)
463{
464	struct sigaction sa;
465
466#if defined(__alpha__) || defined(__arm__)
467	int rv, val;
468	size_t len = sizeof(val);
469	rv = sysctlbyname("machdep.unaligned_sigbus", &val, &len, NULL, 0);
470	ATF_REQUIRE(rv == 0);
471	if (val == 0)
472		atf_tc_skip("No SIGBUS signal for unaligned accesses");
473#endif
474
475	/* m68k (except sun2) never issue SIGBUS (PR lib/49653) */
476	if (strcmp(MACHINE_ARCH, "m68k") == 0)
477		atf_tc_skip("No SIGBUS signal for unaligned accesses");
478
479	sa.sa_flags = SA_SIGINFO;
480	sa.sa_sigaction = sigbus_action;
481	sigemptyset(&sa.sa_mask);
482	sigaction(SIGBUS, &sa, NULL);
483
484	/* Enable alignment checks for x86. 0x40000 is PSL_AC. */
485#if defined(__i386__)
486	__asm__("pushf; orl $0x40000, (%esp); popf");
487#elif defined(__amd64__)
488	__asm__("pushf; orl $0x40000, (%rsp); popf");
489#endif
490
491	addr = calloc(2, sizeof(int));
492	ATF_REQUIRE(addr != NULL);
493
494	if (isQEMU())
495		atf_tc_expect_fail("QEMU fails to trap unaligned accesses");
496
497	/* Force an unaligned access */
498	addr++;
499	printf("now trying to access unaligned address %p\n", addr);
500	ATF_REQUIRE_EQ(*(volatile int *)addr, 0);
501
502	atf_tc_fail("Test did not fault as expected");
503}
504
505ATF_TP_ADD_TCS(tp)
506{
507
508	ATF_TP_ADD_TC(tp, sigalarm);
509	ATF_TP_ADD_TC(tp, sigchild_normal);
510	ATF_TP_ADD_TC(tp, sigchild_dump);
511	ATF_TP_ADD_TC(tp, sigchild_kill);
512	ATF_TP_ADD_TC(tp, sigfpe_flt);
513	ATF_TP_ADD_TC(tp, sigfpe_int);
514	ATF_TP_ADD_TC(tp, sigsegv);
515	ATF_TP_ADD_TC(tp, sigbus_adraln);
516
517	return atf_no_error();
518}
519