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