xref: /netbsd-src/tests/kernel/h_segv.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
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