h_segv.c revision 1.5
11.5Skamil/*	$NetBSD: h_segv.c,v 1.5 2018/05/27 17:04:45 kamil 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.5Skamil__RCSID("$NetBSD: h_segv.c,v 1.5 2018/05/27 17:04:45 kamil Exp $");
331.1Schristos
341.4Skamil#include <sys/types.h>
351.5Skamil#include <sys/mman.h>
361.4Skamil#include <sys/ptrace.h>
371.1Schristos#include <stdio.h>
381.1Schristos#include <string.h>
391.1Schristos#include <stdlib.h>
401.1Schristos#include <unistd.h>
411.1Schristos#include <signal.h>
421.1Schristos#include <err.h>
431.1Schristos
441.1Schristosstatic int flags;
451.1Schristos#define F_RECURSE 	1
461.1Schristos#define F_HANDLE	2
471.1Schristos#define F_MASK		4
481.3Skamil#define F_IGNORE	8
491.1Schristos
501.1Schristosstatic struct {
511.1Schristos	const char *n;
521.1Schristos	int v;
531.1Schristos} nv[] = {
541.1Schristos	{ "recurse",	F_RECURSE },
551.1Schristos	{ "handle",	F_HANDLE },
561.1Schristos	{ "mask",	F_MASK },
571.3Skamil	{ "ignore",	F_IGNORE }
581.1Schristos};
591.1Schristos
601.4Skamilstatic int sig;
611.4Skamilstatic struct {
621.4Skamil	const char *n;
631.4Skamil	int v;
641.4Skamil} sn[] = {
651.4Skamil	{ "segv",	SIGSEGV },
661.5Skamil	{ "trap",	SIGTRAP },
671.5Skamil	{ "ill",	SIGILL },
681.5Skamil	{ "fpe",	SIGFPE },
691.5Skamil	{ "bus",	SIGBUS }
701.4Skamil};
711.4Skamil
721.1Schristosstatic void
731.5Skamiltrigger_segv(void)
741.5Skamil{
751.5Skamil	volatile int *p = (int *)(intptr_t)atoi("0");
761.5Skamil
771.5Skamil	*p = 1;
781.5Skamil}
791.5Skamil
801.5Skamilstatic void
811.5Skamiltrigger_trap(void)
821.1Schristos{
831.5Skamil
841.4Skamil#ifdef PTRACE_BREAKPOINT_ASM
851.5Skamil	PTRACE_BREAKPOINT_ASM;
861.5Skamil#else
871.5Skamil	/* port me */
881.5Skamil#endif
891.5Skamil}
901.5Skamil
911.5Skamilstatic void
921.5Skamiltrigger_ill(void)
931.5Skamil{
941.5Skamil
951.5Skamil#ifdef PTRACE_ILLEGAL_ASM
961.5Skamil	PTRACE_ILLEGAL_ASM;
971.4Skamil#else
981.5Skamil	/* port me */
991.5Skamil#endif
1001.5Skamil}
1011.5Skamil
1021.5Skamilstatic void
1031.5Skamiltrigger_fpe(void)
1041.5Skamil{
1051.5Skamil	volatile int a = getpid();
1061.5Skamil	volatile int b = strtol("0", NULL, 0);
1071.5Skamil
1081.5Skamil	usleep(a/b);
1091.5Skamil}
1101.5Skamil
1111.5Skamilstatic void
1121.5Skamiltrigger_bus(void)
1131.5Skamil{
1141.5Skamil	FILE *fp;
1151.5Skamil	char *p;
1161.5Skamil
1171.5Skamil	/* Open an empty file for writing. */
1181.5Skamil	fp = tmpfile();
1191.5Skamil	if (fp == NULL)
1201.5Skamil		err(EXIT_FAILURE, "tmpfile");
1211.5Skamil
1221.5Skamil	/* Map an empty file with mmap(2) to a pointer. */
1231.5Skamil	p = mmap(0, 1, PROT_WRITE, MAP_PRIVATE, fileno(fp), 0);
1241.5Skamil	if (p == MAP_FAILED)
1251.5Skamil		err(EXIT_FAILURE, "mmap");
1261.5Skamil
1271.5Skamil	/* Invalid memory access causes CPU trap, translated to SIGBUS */
1281.5Skamil	*p = 'a';
1291.5Skamil}
1301.5Skamil
1311.5Skamilstatic void
1321.5Skamiltrigger(void)
1331.5Skamil{
1341.5Skamil
1351.5Skamil	switch (sig) {
1361.5Skamil	case SIGSEGV:
1371.5Skamil		trigger_segv();
1381.5Skamil		break;
1391.5Skamil	case SIGTRAP:
1401.5Skamil		trigger_trap();
1411.5Skamil		break;
1421.5Skamil	case SIGILL:
1431.5Skamil		trigger_ill();
1441.5Skamil		break;
1451.5Skamil	case SIGFPE:
1461.5Skamil		trigger_fpe();
1471.5Skamil		break;
1481.5Skamil	case SIGBUS:
1491.5Skamil		trigger_bus();
1501.5Skamil		break;
1511.5Skamil	default:
1521.5Skamil		break;
1531.4Skamil	}
1541.5Skamil}
1551.5Skamil
1561.5Skamilstatic void
1571.5Skamilfoo(int s)
1581.5Skamil{
1591.5Skamil	char buf[64];
1601.5Skamil	int i = snprintf(buf, sizeof(buf), "got %d\n", s);
1611.5Skamil	write(2, buf, i);
1621.5Skamil
1631.5Skamil	if (flags & F_RECURSE)
1641.5Skamil		trigger();
1651.5Skamil
1661.5Skamil	exit(EXIT_SUCCESS);
1671.1Schristos}
1681.1Schristos
1691.1Schristosstatic __dead void
1701.1Schristosusage(void)
1711.1Schristos{
1721.4Skamil	const char *pname = getprogname();
1731.4Skamil
1741.5Skamil	fprintf(stderr, "Usage: %s segv|trap|ill|fpe|bus "
1751.5Skamil	                "[recurse|mask|handle|ignore] ...\n", pname);
1761.5Skamil
1771.1Schristos	exit(EXIT_FAILURE);
1781.1Schristos}
1791.1Schristos
1801.1Schristosint
1811.1Schristosmain(int argc, char *argv[])
1821.1Schristos{
1831.5Skamil
1841.1Schristos	if (argc == 1)
1851.1Schristos	    usage();
1861.1Schristos
1871.1Schristos	for (int i = 1; i < argc; i++) {
1881.1Schristos		size_t j;
1891.4Skamil		for (j = 0; j < __arraycount(nv); j++) {
1901.1Schristos			if (strcmp(nv[j].n, argv[i]) == 0) {
1911.1Schristos				flags |= nv[j].v;
1921.5Skamil				goto consumed;
1931.1Schristos			}
1941.5Skamil		}
1951.5Skamil		for (j = 0; j < __arraycount(sn); j++) {
1961.4Skamil			if (strcmp(sn[j].n, argv[i]) == 0) {
1971.4Skamil				sig = sn[j].v;
1981.5Skamil				goto consumed;
1991.4Skamil			}
2001.4Skamil		}
2011.5Skamil
2021.5Skamil		usage();
2031.5Skamil
2041.5Skamil	consumed:
2051.5Skamil		continue;
2061.1Schristos	}
2071.1Schristos
2081.4Skamil	if (flags == 0 || sig == 0)
2091.1Schristos		usage();
2101.1Schristos
2111.1Schristos	if (flags & F_HANDLE) {
2121.1Schristos		struct sigaction sa;
2131.1Schristos
2141.1Schristos		sa.sa_flags = SA_RESTART;
2151.1Schristos		sa.sa_handler = foo;
2161.1Schristos		sigemptyset(&sa.sa_mask);
2171.4Skamil		if (sigaction(sig, &sa, NULL) == -1)
2181.1Schristos			err(EXIT_FAILURE, "sigaction");
2191.1Schristos	}
2201.1Schristos
2211.1Schristos	if (flags & F_MASK) {
2221.1Schristos		sigset_t set;
2231.1Schristos
2241.1Schristos		sigemptyset(&set);
2251.4Skamil		sigaddset(&set, sig);
2261.1Schristos		if (sigprocmask(SIG_BLOCK, &set, NULL) == -1)
2271.1Schristos			err(EXIT_FAILURE, "sigprocmask");
2281.1Schristos	}
2291.1Schristos
2301.3Skamil	if (flags & F_IGNORE) {
2311.3Skamil		struct sigaction sa;
2321.3Skamil
2331.3Skamil		memset(&sa, 0, sizeof(sa));
2341.3Skamil		sa.sa_handler = SIG_IGN;
2351.3Skamil		sigemptyset(&sa.sa_mask);
2361.4Skamil		if (sigaction(sig, &sa, NULL) == -1)
2371.3Skamil			err(EXIT_FAILURE, "sigaction");
2381.3Skamil	}
2391.3Skamil
2401.5Skamil	trigger();
2411.5Skamil
2421.1Schristos	return EXIT_SUCCESS;
2431.1Schristos}
244