1 /* $NetBSD: h_segv.c,v 1.7 2018/05/30 17:48:13 kamil Exp $ */ 2 3 /*- 4 * Copyright (c) 2017 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Christos Zoulas. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 #include <sys/cdefs.h> 32 __RCSID("$NetBSD: h_segv.c,v 1.7 2018/05/30 17:48:13 kamil Exp $"); 33 34 #include <sys/types.h> 35 #include <sys/mman.h> 36 #include <sys/ptrace.h> 37 #include <stdio.h> 38 #include <string.h> 39 #include <stdlib.h> 40 #include <unistd.h> 41 #include <signal.h> 42 #include <err.h> 43 44 static int flags; 45 #define F_RECURSE 1 46 #define F_HANDLE 2 47 #define F_MASK 4 48 #define F_IGNORE 8 49 50 static struct { 51 const char *n; 52 int v; 53 } nv[] = { 54 { "recurse", F_RECURSE }, 55 { "handle", F_HANDLE }, 56 { "mask", F_MASK }, 57 { "ignore", F_IGNORE } 58 }; 59 60 static int sig; 61 static struct { 62 const char *n; 63 int v; 64 } sn[] = { 65 { "segv", SIGSEGV }, 66 { "trap", SIGTRAP }, 67 { "ill", SIGILL }, 68 { "fpe", SIGFPE }, 69 { "bus", SIGBUS } 70 }; 71 72 static void 73 trigger_segv(void) 74 { 75 volatile int *p = (int *)(intptr_t)atoi("0"); 76 77 *p = 1; 78 } 79 80 static void 81 trigger_trap(void) 82 { 83 84 #ifdef PTRACE_BREAKPOINT_ASM 85 PTRACE_BREAKPOINT_ASM; 86 #else 87 /* port me */ 88 #endif 89 } 90 91 static void 92 trigger_ill(void) 93 { 94 95 #ifdef PTRACE_ILLEGAL_ASM 96 PTRACE_ILLEGAL_ASM; 97 #else 98 /* port me */ 99 #endif 100 } 101 102 static void 103 trigger_fpe(void) 104 { 105 volatile int a = getpid(); 106 volatile int b = strtol("0", NULL, 0); 107 108 usleep(a/b); 109 } 110 111 static void 112 trigger_bus(void) 113 { 114 FILE *fp; 115 char *p; 116 117 /* Open an empty file for writing. */ 118 fp = tmpfile(); 119 if (fp == NULL) 120 err(EXIT_FAILURE, "tmpfile"); 121 122 /* 123 * Map an empty file with mmap(2) to a pointer. 124 * 125 * PROT_READ handles read-modify-write sequences emitted for 126 * certain combinations of CPUs and compilers (e.g. Alpha AXP). 127 */ 128 p = mmap(0, 1, PROT_READ|PROT_WRITE, MAP_PRIVATE, fileno(fp), 0); 129 if (p == MAP_FAILED) 130 err(EXIT_FAILURE, "mmap"); 131 132 /* Invalid memory access causes CPU trap, translated to SIGBUS */ 133 *p = 'a'; 134 } 135 136 static void 137 trigger(void) 138 { 139 140 switch (sig) { 141 case SIGSEGV: 142 trigger_segv(); 143 break; 144 case SIGTRAP: 145 trigger_trap(); 146 break; 147 case SIGILL: 148 trigger_ill(); 149 break; 150 case SIGFPE: 151 trigger_fpe(); 152 break; 153 case SIGBUS: 154 trigger_bus(); 155 break; 156 default: 157 break; 158 } 159 } 160 161 static void 162 foo(int s) 163 { 164 char buf[64]; 165 int i = snprintf(buf, sizeof(buf), "got %d\n", s); 166 write(2, buf, i); 167 168 if (flags & F_RECURSE) 169 trigger(); 170 171 exit(EXIT_SUCCESS); 172 } 173 174 static __dead void 175 usage(void) 176 { 177 const char *pname = getprogname(); 178 179 fprintf(stderr, "Usage: %s segv|trap|ill|fpe|bus " 180 "[recurse|mask|handle|ignore] ...\n", pname); 181 182 exit(EXIT_FAILURE); 183 } 184 185 int 186 main(int argc, char *argv[]) 187 { 188 189 if (argc == 1) 190 usage(); 191 192 for (int i = 1; i < argc; i++) { 193 size_t j; 194 for (j = 0; j < __arraycount(nv); j++) { 195 if (strcmp(nv[j].n, argv[i]) == 0) { 196 flags |= nv[j].v; 197 goto consumed; 198 } 199 } 200 for (j = 0; j < __arraycount(sn); j++) { 201 if (strcmp(sn[j].n, argv[i]) == 0) { 202 sig = sn[j].v; 203 goto consumed; 204 } 205 } 206 207 usage(); 208 209 consumed: 210 continue; 211 } 212 213 if (flags == 0 || sig == 0) 214 usage(); 215 216 if (flags & F_HANDLE) { 217 struct sigaction sa; 218 219 sa.sa_flags = SA_RESTART; 220 sa.sa_handler = foo; 221 sigemptyset(&sa.sa_mask); 222 if (sigaction(sig, &sa, NULL) == -1) 223 err(EXIT_FAILURE, "sigaction"); 224 } 225 226 if (flags & F_MASK) { 227 sigset_t set; 228 229 sigemptyset(&set); 230 sigaddset(&set, sig); 231 if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) 232 err(EXIT_FAILURE, "sigprocmask"); 233 } 234 235 if (flags & F_IGNORE) { 236 struct sigaction sa; 237 238 memset(&sa, 0, sizeof(sa)); 239 sa.sa_handler = SIG_IGN; 240 sigemptyset(&sa.sa_mask); 241 if (sigaction(sig, &sa, NULL) == -1) 242 err(EXIT_FAILURE, "sigaction"); 243 } 244 245 trigger(); 246 247 return EXIT_SUCCESS; 248 } 249