h_segv.c revision 1.15
11.15Sriastrad/* $NetBSD: h_segv.c,v 1.15 2024/05/14 15:54:16 riastradh Exp $ */ 21.1Schristos 31.1Schristos/*- 41.1Schristos * Copyright (c) 2017 The NetBSD Foundation, Inc. 51.1Schristos * All rights reserved. 61.1Schristos * 71.1Schristos * This code is derived from software contributed to The NetBSD Foundation 81.1Schristos * by Christos Zoulas. 91.1Schristos * 101.1Schristos * Redistribution and use in source and binary forms, with or without 111.1Schristos * modification, are permitted provided that the following conditions 121.1Schristos * are met: 131.1Schristos * 1. Redistributions of source code must retain the above copyright 141.1Schristos * notice, this list of conditions and the following disclaimer. 151.1Schristos * 2. Redistributions in binary form must reproduce the above copyright 161.1Schristos * notice, this list of conditions and the following disclaimer in the 171.1Schristos * documentation and/or other materials provided with the distribution. 181.1Schristos * 191.1Schristos * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 201.1Schristos * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 211.1Schristos * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 221.1Schristos * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 231.1Schristos * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 241.1Schristos * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 251.1Schristos * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 261.1Schristos * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 271.1Schristos * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 281.1Schristos * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 291.1Schristos * POSSIBILITY OF SUCH DAMAGE. 301.1Schristos */ 311.1Schristos#include <sys/cdefs.h> 321.15Sriastrad__RCSID("$NetBSD: h_segv.c,v 1.15 2024/05/14 15:54:16 riastradh Exp $"); 331.10Sriastrad 341.10Sriastrad#define __TEST_FENV 351.1Schristos 361.4Skamil#include <sys/types.h> 371.5Skamil#include <sys/mman.h> 381.4Skamil#include <sys/ptrace.h> 391.8Sriastrad 401.8Sriastrad#include <err.h> 411.9Sriastrad#include <fenv.h> 421.12Schristos#if (__arm__ && !__SOFTFP__) || __aarch64__ 431.11Smartin#include <ieeefp.h> /* only need for ARM Cortex/Neon hack */ 441.12Schristos#endif 451.8Sriastrad#include <signal.h> 461.1Schristos#include <stdio.h> 471.8Sriastrad#include <stdlib.h> 481.1Schristos#include <string.h> 491.1Schristos#include <unistd.h> 501.1Schristos 511.1Schristosstatic int flags; 521.1Schristos#define F_RECURSE 1 531.1Schristos#define F_HANDLE 2 541.1Schristos#define F_MASK 4 551.3Skamil#define F_IGNORE 8 561.11Smartin#define F_CHECK 16 571.1Schristos 581.1Schristosstatic struct { 591.1Schristos const char *n; 601.1Schristos int v; 611.1Schristos} nv[] = { 621.1Schristos { "recurse", F_RECURSE }, 631.1Schristos { "handle", F_HANDLE }, 641.1Schristos { "mask", F_MASK }, 651.11Smartin { "ignore", F_IGNORE }, 661.11Smartin { "check", F_CHECK } 671.1Schristos}; 681.1Schristos 691.4Skamilstatic int sig; 701.4Skamilstatic struct { 711.4Skamil const char *n; 721.4Skamil int v; 731.4Skamil} sn[] = { 741.4Skamil { "segv", SIGSEGV }, 751.5Skamil { "trap", SIGTRAP }, 761.5Skamil { "ill", SIGILL }, 771.5Skamil { "fpe", SIGFPE }, 781.5Skamil { "bus", SIGBUS } 791.4Skamil}; 801.4Skamil 811.1Schristosstatic void 821.5Skamiltrigger_segv(void) 831.5Skamil{ 841.5Skamil volatile int *p = (int *)(intptr_t)atoi("0"); 851.5Skamil 861.5Skamil *p = 1; 871.5Skamil} 881.5Skamil 891.5Skamilstatic void 901.5Skamiltrigger_trap(void) 911.1Schristos{ 921.5Skamil 931.4Skamil#ifdef PTRACE_BREAKPOINT_ASM 941.5Skamil PTRACE_BREAKPOINT_ASM; 951.5Skamil#else 961.5Skamil /* port me */ 971.5Skamil#endif 981.5Skamil} 991.5Skamil 1001.5Skamilstatic void 1011.5Skamiltrigger_ill(void) 1021.5Skamil{ 1031.5Skamil 1041.5Skamil#ifdef PTRACE_ILLEGAL_ASM 1051.5Skamil PTRACE_ILLEGAL_ASM; 1061.4Skamil#else 1071.5Skamil /* port me */ 1081.5Skamil#endif 1091.5Skamil} 1101.5Skamil 1111.5Skamilstatic void 1121.11Smartincheck_fpe(void) 1131.11Smartin{ 1141.11Smartin#if (__arm__ && !__SOFTFP__) || __aarch64__ 1151.11Smartin /* 1161.14Skamil * Some NEON fpus do not trap on IEEE 754 FP exceptions. 1171.13Smartin * Skip these tests if running on them and compiled for 1181.11Smartin * hard float. 1191.11Smartin */ 1201.11Smartin if (0 == fpsetmask(fpsetmask(FP_X_INV))) { 1211.13Smartin printf("FPU does not implement traps on FP exceptions\n"); 1221.11Smartin exit(EXIT_FAILURE); 1231.11Smartin } 1241.15Sriastrad#elif defined __riscv__ 1251.15Sriastrad printf("RISC-V does not support floating-point exception traps\n"); 1261.15Sriastrad exit(EXIT_FAILURE); 1271.11Smartin#endif 1281.11Smartin exit(EXIT_SUCCESS); 1291.11Smartin} 1301.11Smartin 1311.15Sriastradvolatile int ignore_result; 1321.15Sriastrad 1331.11Smartinstatic void 1341.5Skamiltrigger_fpe(void) 1351.5Skamil{ 1361.9Sriastrad volatile double a = getpid(); 1371.9Sriastrad volatile double b = strtol("0", NULL, 0); 1381.5Skamil 1391.10Sriastrad#ifdef __HAVE_FENV 1401.9Sriastrad feenableexcept(FE_ALL_EXCEPT); 1411.10Sriastrad#endif 1421.9Sriastrad 1431.15Sriastrad /* 1441.15Sriastrad * Try to trigger SIGFPE either by dividing by zero (which is 1451.15Sriastrad * defined to raise FE_DIVBYZERO, but may just return infinity 1461.15Sriastrad * without trapping the exception) or by converting infinity to 1471.15Sriastrad * integer. 1481.15Sriastrad */ 1491.15Sriastrad ignore_result = (int)(a/b); 1501.5Skamil} 1511.5Skamil 1521.5Skamilstatic void 1531.5Skamiltrigger_bus(void) 1541.5Skamil{ 1551.5Skamil FILE *fp; 1561.5Skamil char *p; 1571.5Skamil 1581.5Skamil /* Open an empty file for writing. */ 1591.5Skamil fp = tmpfile(); 1601.5Skamil if (fp == NULL) 1611.5Skamil err(EXIT_FAILURE, "tmpfile"); 1621.5Skamil 1631.7Skamil /* 1641.7Skamil * Map an empty file with mmap(2) to a pointer. 1651.7Skamil * 1661.7Skamil * PROT_READ handles read-modify-write sequences emitted for 1671.7Skamil * certain combinations of CPUs and compilers (e.g. Alpha AXP). 1681.7Skamil */ 1691.6Skamil p = mmap(0, 1, PROT_READ|PROT_WRITE, MAP_PRIVATE, fileno(fp), 0); 1701.5Skamil if (p == MAP_FAILED) 1711.5Skamil err(EXIT_FAILURE, "mmap"); 1721.5Skamil 1731.5Skamil /* Invalid memory access causes CPU trap, translated to SIGBUS */ 1741.5Skamil *p = 'a'; 1751.5Skamil} 1761.5Skamil 1771.5Skamilstatic void 1781.5Skamiltrigger(void) 1791.5Skamil{ 1801.5Skamil 1811.5Skamil switch (sig) { 1821.5Skamil case SIGSEGV: 1831.5Skamil trigger_segv(); 1841.5Skamil break; 1851.5Skamil case SIGTRAP: 1861.5Skamil trigger_trap(); 1871.5Skamil break; 1881.5Skamil case SIGILL: 1891.5Skamil trigger_ill(); 1901.5Skamil break; 1911.5Skamil case SIGFPE: 1921.5Skamil trigger_fpe(); 1931.5Skamil break; 1941.5Skamil case SIGBUS: 1951.5Skamil trigger_bus(); 1961.5Skamil break; 1971.5Skamil default: 1981.5Skamil break; 1991.4Skamil } 2001.5Skamil} 2011.5Skamil 2021.5Skamilstatic void 2031.5Skamilfoo(int s) 2041.5Skamil{ 2051.5Skamil char buf[64]; 2061.5Skamil int i = snprintf(buf, sizeof(buf), "got %d\n", s); 2071.5Skamil write(2, buf, i); 2081.5Skamil 2091.5Skamil if (flags & F_RECURSE) 2101.5Skamil trigger(); 2111.5Skamil 2121.5Skamil exit(EXIT_SUCCESS); 2131.1Schristos} 2141.1Schristos 2151.1Schristosstatic __dead void 2161.1Schristosusage(void) 2171.1Schristos{ 2181.4Skamil const char *pname = getprogname(); 2191.4Skamil 2201.5Skamil fprintf(stderr, "Usage: %s segv|trap|ill|fpe|bus " 2211.11Smartin "[recurse|mask|handle|ignore|check] ...\n", pname); 2221.5Skamil 2231.1Schristos exit(EXIT_FAILURE); 2241.1Schristos} 2251.1Schristos 2261.1Schristosint 2271.1Schristosmain(int argc, char *argv[]) 2281.1Schristos{ 2291.5Skamil 2301.1Schristos if (argc == 1) 2311.1Schristos usage(); 2321.1Schristos 2331.1Schristos for (int i = 1; i < argc; i++) { 2341.1Schristos size_t j; 2351.4Skamil for (j = 0; j < __arraycount(nv); j++) { 2361.1Schristos if (strcmp(nv[j].n, argv[i]) == 0) { 2371.1Schristos flags |= nv[j].v; 2381.5Skamil goto consumed; 2391.1Schristos } 2401.5Skamil } 2411.5Skamil for (j = 0; j < __arraycount(sn); j++) { 2421.4Skamil if (strcmp(sn[j].n, argv[i]) == 0) { 2431.4Skamil sig = sn[j].v; 2441.5Skamil goto consumed; 2451.4Skamil } 2461.4Skamil } 2471.5Skamil 2481.5Skamil usage(); 2491.5Skamil 2501.5Skamil consumed: 2511.5Skamil continue; 2521.1Schristos } 2531.1Schristos 2541.4Skamil if (flags == 0 || sig == 0) 2551.1Schristos usage(); 2561.1Schristos 2571.11Smartin if (flags & F_CHECK && sig != SIGFPE) { 2581.11Smartin fprintf(stderr, "can only check for fpe support\n"); 2591.11Smartin return 1; 2601.11Smartin } 2611.11Smartin if (flags & F_CHECK) 2621.11Smartin check_fpe(); 2631.11Smartin 2641.1Schristos if (flags & F_HANDLE) { 2651.1Schristos struct sigaction sa; 2661.1Schristos 2671.1Schristos sa.sa_flags = SA_RESTART; 2681.1Schristos sa.sa_handler = foo; 2691.1Schristos sigemptyset(&sa.sa_mask); 2701.4Skamil if (sigaction(sig, &sa, NULL) == -1) 2711.1Schristos err(EXIT_FAILURE, "sigaction"); 2721.1Schristos } 2731.1Schristos 2741.1Schristos if (flags & F_MASK) { 2751.1Schristos sigset_t set; 2761.1Schristos 2771.1Schristos sigemptyset(&set); 2781.4Skamil sigaddset(&set, sig); 2791.1Schristos if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) 2801.1Schristos err(EXIT_FAILURE, "sigprocmask"); 2811.1Schristos } 2821.1Schristos 2831.3Skamil if (flags & F_IGNORE) { 2841.3Skamil struct sigaction sa; 2851.3Skamil 2861.3Skamil memset(&sa, 0, sizeof(sa)); 2871.3Skamil sa.sa_handler = SIG_IGN; 2881.3Skamil sigemptyset(&sa.sa_mask); 2891.4Skamil if (sigaction(sig, &sa, NULL) == -1) 2901.3Skamil err(EXIT_FAILURE, "sigaction"); 2911.3Skamil } 2921.3Skamil 2931.5Skamil trigger(); 2941.5Skamil 2951.1Schristos return EXIT_SUCCESS; 2961.1Schristos} 297