t_siginfo.c revision 1.16 1 /* $NetBSD: t_siginfo.c,v 1.16 2012/04/22 08:52:26 martin 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 #include <atf-c/config.h>
31
32 #include <sys/inttypes.h>
33 #include <sys/resource.h>
34 #include <sys/time.h>
35 #include <sys/ucontext.h>
36 #include <sys/wait.h>
37
38 #include <assert.h>
39 #include <signal.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <setjmp.h>
45 #include <float.h>
46
47 #ifdef _FLOAT_IEEE754
48 #include <ieeefp.h>
49 #endif
50
51 /* for sigbus */
52 char *addr;
53
54 /* for sigchild */
55 pid_t child;
56 int code;
57 int status;
58
59 /* for sigfpe */
60 sig_atomic_t fltdiv_signalled = 0;
61 sig_atomic_t intdiv_signalled = 0;
62
63 static void
64 sig_debug(int signo, siginfo_t *info, ucontext_t *ctx)
65 {
66 unsigned int i;
67
68 printf("%d %p %p\n", signo, info, ctx);
69 if (info != NULL) {
70 printf("si_signo=%d\n", info->si_signo);
71 printf("si_errno=%d\n", info->si_errno);
72 printf("si_code=%d\n", info->si_code);
73 printf("si_value.sival_int=%d\n", info->si_value.sival_int);
74 }
75 if (ctx != NULL) {
76 printf("uc_flags 0x%x\n", ctx->uc_flags);
77 printf("uc_link %p\n", ctx->uc_link);
78 for (i = 0; i < __arraycount(ctx->uc_sigmask.__bits); i++)
79 printf("uc_sigmask[%d] 0x%x\n", i,
80 ctx->uc_sigmask.__bits[i]);
81 printf("uc_stack %p %lu 0x%x\n", ctx->uc_stack.ss_sp,
82 (unsigned long)ctx->uc_stack.ss_size,
83 ctx->uc_stack.ss_flags);
84 for (i = 0; i < __arraycount(ctx->uc_mcontext.__gregs); i++)
85 printf("uc_mcontext.greg[%d] 0x%lx\n", i,
86 (long)ctx->uc_mcontext.__gregs[i]);
87 }
88 }
89
90 static void
91 sigalrm_action(int signo, siginfo_t *info, void *ptr)
92 {
93
94 sig_debug(signo, info, (ucontext_t *)ptr);
95
96 ATF_REQUIRE_EQ(info->si_signo, SIGALRM);
97 ATF_REQUIRE_EQ(info->si_code, SI_TIMER);
98 ATF_REQUIRE_EQ(info->si_value.sival_int, ITIMER_REAL);
99
100 atf_tc_pass();
101 /* NOTREACHED */
102 }
103
104 ATF_TC(sigalarm);
105
106 ATF_TC_HEAD(sigalarm, tc)
107 {
108
109 atf_tc_set_md_var(tc, "descr",
110 "Checks that signal trampoline correctly calls SIGALRM handler");
111 }
112
113 ATF_TC_BODY(sigalarm, tc)
114 {
115 struct sigaction sa;
116 sa.sa_flags = SA_SIGINFO;
117 sa.sa_sigaction = sigalrm_action;
118 sigemptyset(&sa.sa_mask);
119 sigaction(SIGALRM, &sa, NULL);
120 for (;;) {
121 alarm(1);
122 sleep(1);
123 }
124 atf_tc_fail("SIGALRM handler wasn't called");
125 }
126
127 static void
128 sigchild_action(int signo, siginfo_t *info, void *ptr)
129 {
130 if (info != NULL) {
131 printf("info=%p\n", info);
132 printf("ptr=%p\n", ptr);
133 printf("si_signo=%d\n", info->si_signo);
134 printf("si_errno=%d\n", info->si_errno);
135 printf("si_code=%d\n", info->si_code);
136 printf("si_uid=%d\n", info->si_uid);
137 printf("si_pid=%d\n", info->si_pid);
138 printf("si_status=%d\n", info->si_status);
139 printf("si_utime=%lu\n", (unsigned long int)info->si_utime);
140 printf("si_stime=%lu\n", (unsigned long int)info->si_stime);
141 }
142 ATF_REQUIRE_EQ(info->si_code, code);
143 ATF_REQUIRE_EQ(info->si_signo, SIGCHLD);
144 ATF_REQUIRE_EQ(info->si_uid, getuid());
145 ATF_REQUIRE_EQ(info->si_pid, child);
146 if (WIFEXITED(info->si_status))
147 ATF_REQUIRE_EQ(WEXITSTATUS(info->si_status), status);
148 else if (WIFSTOPPED(info->si_status))
149 ATF_REQUIRE_EQ(WSTOPSIG(info->si_status), status);
150 else if (WIFSIGNALED(info->si_status))
151 ATF_REQUIRE_EQ(WTERMSIG(info->si_status), status);
152 }
153
154 static void
155 setchildhandler(void (*action)(int, siginfo_t *, void *))
156 {
157 struct sigaction sa;
158 sa.sa_flags = SA_SIGINFO;
159 sa.sa_sigaction = action;
160 sigemptyset(&sa.sa_mask);
161 sigaction(SIGCHLD, &sa, NULL);
162 }
163
164 static void
165 sigchild_setup(void)
166 {
167 sigset_t set;
168 struct rlimit rlim;
169
170 (void)getrlimit(RLIMIT_CORE, &rlim);
171 rlim.rlim_cur = rlim.rlim_max;
172 (void)setrlimit(RLIMIT_CORE, &rlim);
173
174 setchildhandler(sigchild_action);
175 sigemptyset(&set);
176 sigaddset(&set, SIGCHLD);
177 sigprocmask(SIG_BLOCK, &set, NULL);
178 }
179
180 ATF_TC(sigchild_normal);
181 ATF_TC_HEAD(sigchild_normal, tc)
182 {
183
184 atf_tc_set_md_var(tc, "descr",
185 "Checks that signal trampoline correctly calls SIGCHLD handler "
186 "when child exits normally");
187 }
188
189 ATF_TC_BODY(sigchild_normal, tc)
190 {
191 sigset_t set;
192
193 sigchild_setup();
194
195 status = 25;
196 code = CLD_EXITED;
197
198 switch ((child = fork())) {
199 case 0:
200 sleep(1);
201 exit(status);
202 case -1:
203 atf_tc_fail("fork failed");
204 default:
205 sigemptyset(&set);
206 sigsuspend(&set);
207 }
208 }
209
210 ATF_TC(sigchild_dump);
211 ATF_TC_HEAD(sigchild_dump, tc)
212 {
213
214 atf_tc_set_md_var(tc, "descr",
215 "Checks that signal trampoline correctly calls SIGCHLD handler "
216 "when child segfaults");
217 }
218
219 ATF_TC_BODY(sigchild_dump, tc)
220 {
221 sigset_t set;
222
223 sigchild_setup();
224
225 status = SIGSEGV;
226 code = CLD_DUMPED;
227
228 switch ((child = fork())) {
229 case 0:
230 sleep(1);
231 *(volatile long *)0 = 0;
232 atf_tc_fail("Child did not segfault");
233 /* NOTREACHED */
234 case -1:
235 atf_tc_fail("fork failed");
236 default:
237 sigemptyset(&set);
238 sigsuspend(&set);
239 }
240 }
241
242 ATF_TC(sigchild_kill);
243 ATF_TC_HEAD(sigchild_kill, tc)
244 {
245
246 atf_tc_set_md_var(tc, "descr",
247 "Checks that signal trampoline correctly calls SIGCHLD handler "
248 "when child is killed");
249 }
250
251 ATF_TC_BODY(sigchild_kill, tc)
252 {
253 sigset_t set;
254
255 sigchild_setup();
256
257 status = SIGPIPE;
258 code = CLD_KILLED;
259
260 switch ((child = fork())) {
261 case 0:
262 sigemptyset(&set);
263 sigsuspend(&set);
264 break;
265 case -1:
266 atf_tc_fail("fork failed");
267 default:
268 kill(child, SIGPIPE);
269 sigemptyset(&set);
270 sigsuspend(&set);
271 }
272 }
273
274 static sigjmp_buf sigfpe_flt_env;
275 static void
276 sigfpe_flt_action(int signo, siginfo_t *info, void *ptr)
277 {
278
279 sig_debug(signo, info, (ucontext_t *)ptr);
280
281 if (fltdiv_signalled++ != 0)
282 atf_tc_fail("FPE handler called more than once");
283
284 ATF_REQUIRE_EQ(info->si_signo, SIGFPE);
285 ATF_REQUIRE_EQ(info->si_code, FPE_FLTDIV);
286 ATF_REQUIRE_EQ(info->si_errno, 0);
287
288 siglongjmp(sigfpe_flt_env, 1);
289 }
290
291 ATF_TC(sigfpe_flt);
292 ATF_TC_HEAD(sigfpe_flt, tc)
293 {
294
295 atf_tc_set_md_var(tc, "descr",
296 "Checks that signal trampoline correctly calls SIGFPE handler "
297 "for floating div-by-zero");
298 }
299
300 ATF_TC_BODY(sigfpe_flt, tc)
301 {
302 struct sigaction sa;
303 double d = strtod("0", NULL);
304
305 if (system("cpuctl identify 0 | grep -q QEMU") == 0)
306 atf_tc_skip("Test does not run correctly under qemu");
307 if (system("cpuctl identify 0 | grep -q "
308 "'cpu0: Intel Pentium II (Klamath) (686-class), id 0x633'") == 0)
309 atf_tc_skip("Test does not run correctly under qemu "
310 "(heuristic match)");
311 if (strcmp(atf_config_get("atf_arch"),"powerpc") == 0)
312 atf_tc_skip("Test not valid on powerpc");
313 if (sigsetjmp(sigfpe_flt_env, 0) == 0) {
314 sa.sa_flags = SA_SIGINFO;
315 sa.sa_sigaction = sigfpe_flt_action;
316 sigemptyset(&sa.sa_mask);
317 sigaction(SIGFPE, &sa, NULL);
318 #ifdef _FLOAT_IEEE754
319 fpsetmask(FP_X_INV|FP_X_DZ|FP_X_OFL|FP_X_UFL|FP_X_IMP);
320 #endif
321 printf("%g\n", 1 / d);
322 }
323 if (fltdiv_signalled == 0)
324 atf_tc_fail("FPE signal handler was not invoked");
325 }
326
327 static sigjmp_buf sigfpe_int_env;
328 static void
329 sigfpe_int_action(int signo, siginfo_t *info, void *ptr)
330 {
331
332 sig_debug(signo, info, (ucontext_t *)ptr);
333
334 if (intdiv_signalled++ != 0)
335 atf_tc_fail("INTDIV handler called more than once");
336
337 ATF_REQUIRE_EQ(info->si_signo, SIGFPE);
338 ATF_REQUIRE_EQ(info->si_code, FPE_INTDIV);
339 atf_tc_expect_pass();
340 ATF_REQUIRE_EQ(info->si_errno, 0);
341
342 siglongjmp(sigfpe_int_env, 1);
343 }
344
345 ATF_TC(sigfpe_int);
346 ATF_TC_HEAD(sigfpe_int, tc)
347 {
348
349 atf_tc_set_md_var(tc, "descr",
350 "Checks that signal trampoline correctly calls SIGFPE handler "
351 "for integer div-by-zero (PR port-i386/43655)");
352 }
353
354 ATF_TC_BODY(sigfpe_int, tc)
355 {
356 struct sigaction sa;
357 long l = strtol("0", NULL, 10);
358
359 if (strcmp(atf_config_get("atf_arch"),"powerpc") == 0)
360 atf_tc_skip("Test not valid on powerpc");
361 if (sigsetjmp(sigfpe_int_env, 0) == 0) {
362 sa.sa_flags = SA_SIGINFO;
363 sa.sa_sigaction = sigfpe_int_action;
364 sigemptyset(&sa.sa_mask);
365 sigaction(SIGFPE, &sa, NULL);
366 #ifdef _FLOAT_IEEE754
367 fpsetmask(FP_X_INV|FP_X_DZ|FP_X_OFL|FP_X_UFL|FP_X_IMP);
368 #endif
369 printf("%ld\n", 1 / l);
370 }
371 if (intdiv_signalled == 0)
372 atf_tc_fail("FPE signal handler was not invoked");
373 }
374
375 static void
376 sigsegv_action(int signo, siginfo_t *info, void *ptr)
377 {
378
379 sig_debug(signo, info, (ucontext_t *)ptr);
380
381 ATF_REQUIRE_EQ(info->si_signo, SIGSEGV);
382 ATF_REQUIRE_EQ(info->si_errno, 0);
383 ATF_REQUIRE_EQ(info->si_code, SEGV_MAPERR);
384 ATF_REQUIRE_EQ(info->si_addr, (void *)0);
385
386 atf_tc_pass();
387 /* NOTREACHED */
388 }
389
390 ATF_TC(sigsegv);
391 ATF_TC_HEAD(sigsegv, tc)
392 {
393
394 atf_tc_set_md_var(tc, "descr",
395 "Checks that signal trampoline correctly calls SIGSEGV handler");
396 }
397
398 ATF_TC_BODY(sigsegv, tc)
399 {
400 struct sigaction sa;
401
402 sa.sa_flags = SA_SIGINFO;
403 sa.sa_sigaction = sigsegv_action;
404 sigemptyset(&sa.sa_mask);
405 sigaction(SIGSEGV, &sa, NULL);
406
407 *(volatile long *)0 = 0;
408 atf_tc_fail("Test did not fault as expected");
409 }
410
411 static void
412 sigbus_action(int signo, siginfo_t *info, void *ptr)
413 {
414
415 sig_debug(signo, info, (ucontext_t *)ptr);
416
417 ATF_REQUIRE_EQ(info->si_signo, SIGBUS);
418 ATF_REQUIRE_EQ(info->si_errno, 0);
419 ATF_REQUIRE_EQ(info->si_code, BUS_ADRALN);
420
421 #if 0
422 if (strcmp(atf_config_get("atf_arch"), "i386") == 0 ||
423 strcmp(atf_config_get("atf_arch"), "x86_64") == 0) {
424 atf_tc_expect_fail("x86 architecture does not correctly "
425 "report the address where the unaligned access occured");
426 }
427
428 /*
429 * XXX: This is bogus: si_addr is documented as the text address
430 * where the fault occurs, addr is the faulting data address,
431 * see TOG about siginfo_t:
432 *
433 * void * si_addr Address of faulting instruction.
434 *
435 * Is there a portable way to get the accessed data address from
436 * the handler?
437 */
438 ATF_REQUIRE_EQ(info->si_addr, (void *)addr);
439 #endif
440
441 atf_tc_pass();
442 /* NOTREACHED */
443 }
444
445 ATF_TC(sigbus_adraln);
446 ATF_TC_HEAD(sigbus_adraln, tc)
447 {
448
449 atf_tc_set_md_var(tc, "descr",
450 "Checks that signal trampoline correctly calls SIGBUS handler "
451 "for invalid address alignment");
452 }
453
454 ATF_TC_BODY(sigbus_adraln, tc)
455 {
456 struct sigaction sa;
457
458 sa.sa_flags = SA_SIGINFO;
459 sa.sa_sigaction = sigbus_action;
460 sigemptyset(&sa.sa_mask);
461 sigaction(SIGBUS, &sa, NULL);
462
463 /* Enable alignement checks for x86. 0x40000 is PSL_AC. */
464 #if defined(__i386__)
465 __asm__("pushf; orl $0x40000, (%esp); popf");
466 #elif defined(__amd64__)
467 __asm__("pushf; orl $0x40000, (%rsp); popf");
468 #endif
469
470 addr = calloc(2, sizeof(int));
471 ATF_REQUIRE(addr != NULL);
472
473 if (strcmp(atf_config_get("atf_arch"), "i386") == 0 ||
474 strcmp(atf_config_get("atf_arch"), "x86_64") == 0) {
475 if (system("cpuctl identify 0 | grep -q QEMU") == 0) {
476 atf_tc_expect_fail("QEMU fails to trap unaligned "
477 "accesses");
478 }
479 }
480
481 /* Force an unaligned access */
482 addr++;
483 ATF_REQUIRE_EQ(*(volatile int *)addr, 0);
484
485 atf_tc_fail("Test did not fault as expected");
486 }
487
488 ATF_TP_ADD_TCS(tp)
489 {
490
491 ATF_TP_ADD_TC(tp, sigalarm);
492 ATF_TP_ADD_TC(tp, sigchild_normal);
493 ATF_TP_ADD_TC(tp, sigchild_dump);
494 ATF_TP_ADD_TC(tp, sigchild_kill);
495 ATF_TP_ADD_TC(tp, sigfpe_flt);
496 ATF_TP_ADD_TC(tp, sigfpe_int);
497 ATF_TP_ADD_TC(tp, sigsegv);
498 ATF_TP_ADD_TC(tp, sigbus_adraln);
499
500 return atf_no_error();
501 }
502