h_segv.c revision 1.6
1/* $NetBSD: h_segv.c,v 1.6 2018/05/30 17:31:34 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.6 2018/05/30 17:31:34 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 44static int flags; 45#define F_RECURSE 1 46#define F_HANDLE 2 47#define F_MASK 4 48#define F_IGNORE 8 49 50static 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 60static int sig; 61static 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 72static void 73trigger_segv(void) 74{ 75 volatile int *p = (int *)(intptr_t)atoi("0"); 76 77 *p = 1; 78} 79 80static void 81trigger_trap(void) 82{ 83 84#ifdef PTRACE_BREAKPOINT_ASM 85 PTRACE_BREAKPOINT_ASM; 86#else 87 /* port me */ 88#endif 89} 90 91static void 92trigger_ill(void) 93{ 94 95#ifdef PTRACE_ILLEGAL_ASM 96 PTRACE_ILLEGAL_ASM; 97#else 98 /* port me */ 99#endif 100} 101 102static void 103trigger_fpe(void) 104{ 105 volatile int a = getpid(); 106 volatile int b = strtol("0", NULL, 0); 107 108 usleep(a/b); 109} 110 111static void 112trigger_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 /* Map an empty file with mmap(2) to a pointer. */ 123 p = mmap(0, 1, PROT_READ|PROT_WRITE, MAP_PRIVATE, fileno(fp), 0); 124 if (p == MAP_FAILED) 125 err(EXIT_FAILURE, "mmap"); 126 127 /* Invalid memory access causes CPU trap, translated to SIGBUS */ 128 *p = 'a'; 129} 130 131static void 132trigger(void) 133{ 134 135 switch (sig) { 136 case SIGSEGV: 137 trigger_segv(); 138 break; 139 case SIGTRAP: 140 trigger_trap(); 141 break; 142 case SIGILL: 143 trigger_ill(); 144 break; 145 case SIGFPE: 146 trigger_fpe(); 147 break; 148 case SIGBUS: 149 trigger_bus(); 150 break; 151 default: 152 break; 153 } 154} 155 156static void 157foo(int s) 158{ 159 char buf[64]; 160 int i = snprintf(buf, sizeof(buf), "got %d\n", s); 161 write(2, buf, i); 162 163 if (flags & F_RECURSE) 164 trigger(); 165 166 exit(EXIT_SUCCESS); 167} 168 169static __dead void 170usage(void) 171{ 172 const char *pname = getprogname(); 173 174 fprintf(stderr, "Usage: %s segv|trap|ill|fpe|bus " 175 "[recurse|mask|handle|ignore] ...\n", pname); 176 177 exit(EXIT_FAILURE); 178} 179 180int 181main(int argc, char *argv[]) 182{ 183 184 if (argc == 1) 185 usage(); 186 187 for (int i = 1; i < argc; i++) { 188 size_t j; 189 for (j = 0; j < __arraycount(nv); j++) { 190 if (strcmp(nv[j].n, argv[i]) == 0) { 191 flags |= nv[j].v; 192 goto consumed; 193 } 194 } 195 for (j = 0; j < __arraycount(sn); j++) { 196 if (strcmp(sn[j].n, argv[i]) == 0) { 197 sig = sn[j].v; 198 goto consumed; 199 } 200 } 201 202 usage(); 203 204 consumed: 205 continue; 206 } 207 208 if (flags == 0 || sig == 0) 209 usage(); 210 211 if (flags & F_HANDLE) { 212 struct sigaction sa; 213 214 sa.sa_flags = SA_RESTART; 215 sa.sa_handler = foo; 216 sigemptyset(&sa.sa_mask); 217 if (sigaction(sig, &sa, NULL) == -1) 218 err(EXIT_FAILURE, "sigaction"); 219 } 220 221 if (flags & F_MASK) { 222 sigset_t set; 223 224 sigemptyset(&set); 225 sigaddset(&set, sig); 226 if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) 227 err(EXIT_FAILURE, "sigprocmask"); 228 } 229 230 if (flags & F_IGNORE) { 231 struct sigaction sa; 232 233 memset(&sa, 0, sizeof(sa)); 234 sa.sa_handler = SIG_IGN; 235 sigemptyset(&sa.sa_mask); 236 if (sigaction(sig, &sa, NULL) == -1) 237 err(EXIT_FAILURE, "sigaction"); 238 } 239 240 trigger(); 241 242 return EXIT_SUCCESS; 243} 244