1c28bcbdfSIngo Weinhold/*
223338ed5SIngo Weinhold * Copyright 2005-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3c28bcbdfSIngo Weinhold * Distributed under the terms of the MIT License.
4c28bcbdfSIngo Weinhold */
5aff60bb2SIngo Weinhold
623338ed5SIngo Weinhold
78a04709aSIngo Weinhold#undef NDEBUG
88a04709aSIngo Weinhold
98a04709aSIngo Weinhold#include <assert.h>
1023338ed5SIngo Weinhold#include <errno.h>
11c28bcbdfSIngo Weinhold#include <signal.h>
12aff60bb2SIngo Weinhold#include <stdio.h>
1337d96a4cSIngo Weinhold#include <stdlib.h>
1437d96a4cSIngo Weinhold#include <string.h>
1523338ed5SIngo Weinhold#include <unistd.h>
16aff60bb2SIngo Weinhold
17aff60bb2SIngo Weinhold#include <OS.h>
18aff60bb2SIngo Weinhold
19aff60bb2SIngo Weinholdextern const char *__progname;
20aff60bb2SIngo Weinhold
21aff60bb2SIngo Weinhold// usage
22aff60bb2SIngo Weinholdstatic const char *kUsage =
23aff60bb2SIngo Weinhold	"%s <options> [ <mode> ]\n"
24aff60bb2SIngo Weinhold	"Crashes in more or less inovative ways.\n"
25aff60bb2SIngo Weinhold	"\n"
26aff60bb2SIngo Weinhold	"Options:\n"
27e9c4d47aSIngo Weinhold	"  -d                   - call disable_debugger() first\n"
2823338ed5SIngo Weinhold	"  -f, --fork           - fork() and continue in the child\n"
29aff60bb2SIngo Weinhold	"  -h, --help           - print this info text\n"
30180e55a4SIngo Weinhold	"  --multi              - crash in multiple threads\n"
31c28bcbdfSIngo Weinhold	"  --signal             - crash in a signal handler\n"
32b2537f99SIngo Weinhold	"  --thread             - crash in a separate thread\n"
33aff60bb2SIngo Weinhold	"\n"
34aff60bb2SIngo Weinhold	"Modes:\n"
35aff60bb2SIngo Weinhold	"[general]\n"
36aff60bb2SIngo Weinhold	"  segv                 - dereferences a null pointer (default)\n"
37aff60bb2SIngo Weinhold	"  segv2                - strcmp() using a 0x1 pointer\n"
38aff60bb2SIngo Weinhold	"  div                  - executes a division by zero\n"
39aff60bb2SIngo Weinhold	"  debugger             - invokes debugger()\n"
40c28bcbdfSIngo Weinhold	"  assert               - failed assert(), which should invoke the\n"
418a04709aSIngo Weinhold	"                         debugger\n"
42aff60bb2SIngo Weinhold	"\n"
43aff60bb2SIngo Weinhold	"[x86 specific]\n"
44aff60bb2SIngo Weinhold	"  int3                 - executes the int3 (breakpoint) instruction\n"
45aff60bb2SIngo Weinhold	"  protection           - executes an instruction that causes a general\n"
46aff60bb2SIngo Weinhold	"                         protection exception\n";
47aff60bb2SIngo Weinhold
48aff60bb2SIngo Weinhold// application name
49aff60bb2SIngo Weinholdconst char *kAppName = __progname;
50aff60bb2SIngo Weinhold
51aff60bb2SIngo Weinholdstatic void
52aff60bb2SIngo Weinholdprint_usage(bool error)
53aff60bb2SIngo Weinhold{
54aff60bb2SIngo Weinhold	fprintf(error ? stderr : stdout, kUsage, kAppName);
55aff60bb2SIngo Weinhold}
56aff60bb2SIngo Weinhold
57aff60bb2SIngo Weinhold
58aff60bb2SIngo Weinholdstatic void
59aff60bb2SIngo Weinholdprint_usage_and_exit(bool error)
60aff60bb2SIngo Weinhold{
61aff60bb2SIngo Weinhold	print_usage(error);
62aff60bb2SIngo Weinhold	exit(error ? 0 : 1);
63aff60bb2SIngo Weinhold}
64aff60bb2SIngo Weinhold
65aff60bb2SIngo Weinhold
66b2537f99SIngo Weinholdstatic int
67aff60bb2SIngo Weinholdcrash_segv()
68aff60bb2SIngo Weinhold{
69aff60bb2SIngo Weinhold	int *a = 0;
70aff60bb2SIngo Weinhold	*a = 0;
71b2537f99SIngo Weinhold	return 0;
72aff60bb2SIngo Weinhold}
73aff60bb2SIngo Weinhold
74b2537f99SIngo Weinholdstatic int
75aff60bb2SIngo Weinholdcrash_segv2()
76aff60bb2SIngo Weinhold{
77aff60bb2SIngo Weinhold	const char *str = (const char*)0x1;
78b2537f99SIngo Weinhold	return strcmp(str, "Test");
79aff60bb2SIngo Weinhold}
80aff60bb2SIngo Weinhold
815e14f5daSIngo Weinholdstatic int
82aff60bb2SIngo Weinholdcrash_div()
83aff60bb2SIngo Weinhold{
84aff60bb2SIngo Weinhold	int i = 0;
85aff60bb2SIngo Weinhold	i = 1 / i;
865e14f5daSIngo Weinhold	return i;
87aff60bb2SIngo Weinhold}
88aff60bb2SIngo Weinhold
89b2537f99SIngo Weinholdstatic int
90aff60bb2SIngo Weinholdcrash_debugger()
91aff60bb2SIngo Weinhold{
92aff60bb2SIngo Weinhold	debugger("crashing_app() invoked debugger()");
93b2537f99SIngo Weinhold	return 0;
94aff60bb2SIngo Weinhold}
95aff60bb2SIngo Weinhold
968a04709aSIngo Weinhold
978a04709aSIngo Weinholdstatic int
988a04709aSIngo Weinholdcrash_assert()
998a04709aSIngo Weinhold{
1008a04709aSIngo Weinhold	assert(0 > 1);
1018a04709aSIngo Weinhold	return 0;
1028a04709aSIngo Weinhold}
1038a04709aSIngo Weinhold
1048a04709aSIngo Weinhold
1055ffbe7d7SAugustin Cavalier#if __i386__
106aff60bb2SIngo Weinhold
107b2537f99SIngo Weinholdstatic int
108aff60bb2SIngo Weinholdcrash_int3()
109aff60bb2SIngo Weinhold{
110aff60bb2SIngo Weinhold	asm("int3");
111b2537f99SIngo Weinhold	return 0;
112aff60bb2SIngo Weinhold}
113aff60bb2SIngo Weinhold
114b2537f99SIngo Weinholdstatic int
115aff60bb2SIngo Weinholdcrash_protection()
116aff60bb2SIngo Weinhold{
117aff60bb2SIngo Weinhold	asm("movl %0, %%dr7" : : "r"(0));
118b2537f99SIngo Weinhold	return 0;
119aff60bb2SIngo Weinhold}
120aff60bb2SIngo Weinhold
1215ffbe7d7SAugustin Cavalier#endif	// __i386__
122aff60bb2SIngo Weinhold
123aff60bb2SIngo Weinhold
124b2537f99SIngo Weinholdtypedef int crash_function_t();
125b2537f99SIngo Weinhold
126b2537f99SIngo Weinhold
127c28bcbdfSIngo Weinholdstruct Options {
128c28bcbdfSIngo Weinhold	Options()
129c28bcbdfSIngo Weinhold		:
130c28bcbdfSIngo Weinhold		inThread(false),
131180e55a4SIngo Weinhold		multipleThreads(false),
132c28bcbdfSIngo Weinhold		inSignalHandler(false),
13323338ed5SIngo Weinhold		disableDebugger(false),
13423338ed5SIngo Weinhold		fork(false)
135c28bcbdfSIngo Weinhold	{
136c28bcbdfSIngo Weinhold	}
137c28bcbdfSIngo Weinhold
138c28bcbdfSIngo Weinhold	crash_function_t*	function;
139c28bcbdfSIngo Weinhold	bool				inThread;
140180e55a4SIngo Weinhold	bool				multipleThreads;
141c28bcbdfSIngo Weinhold	bool				inSignalHandler;
142c28bcbdfSIngo Weinhold	bool				disableDebugger;
14323338ed5SIngo Weinhold	bool				fork;
144c28bcbdfSIngo Weinhold};
145c28bcbdfSIngo Weinhold
146c28bcbdfSIngo Weinholdstatic Options sOptions;
147c28bcbdfSIngo Weinhold
148c28bcbdfSIngo Weinhold
149b2537f99SIngo Weinholdstatic crash_function_t*
150b2537f99SIngo Weinholdget_crash_function(const char* mode)
151b2537f99SIngo Weinhold{
152b2537f99SIngo Weinhold	if (strcmp(mode, "segv") == 0) {
153b2537f99SIngo Weinhold		return crash_segv;
154b2537f99SIngo Weinhold	} else if (strcmp(mode, "segv2") == 0) {
155b2537f99SIngo Weinhold		return crash_segv2;
156b2537f99SIngo Weinhold	} else if (strcmp(mode, "div") == 0) {
157b2537f99SIngo Weinhold		return (crash_function_t*)crash_div;
158b2537f99SIngo Weinhold	} else if (strcmp(mode, "debugger") == 0) {
159b2537f99SIngo Weinhold		return crash_debugger;
1608a04709aSIngo Weinhold	} else if (strcmp(mode, "assert") == 0) {
1618a04709aSIngo Weinhold		return crash_assert;
1625ffbe7d7SAugustin Cavalier#if __i386__
163b2537f99SIngo Weinhold	} else if (strcmp(mode, "int3") == 0) {
164b2537f99SIngo Weinhold		return crash_int3;
165b2537f99SIngo Weinhold	} else if (strcmp(mode, "protection") == 0) {
166b2537f99SIngo Weinhold		return crash_protection;
1675ffbe7d7SAugustin Cavalier#endif	// __i386__
168b2537f99SIngo Weinhold	}
169b2537f99SIngo Weinhold
170b2537f99SIngo Weinhold	return NULL;
171b2537f99SIngo Weinhold}
172b2537f99SIngo Weinhold
173b2537f99SIngo Weinhold
174c28bcbdfSIngo Weinholdstatic void
175c28bcbdfSIngo Weinholdsignal_handler(int signal)
176c28bcbdfSIngo Weinhold{
177c28bcbdfSIngo Weinhold	sOptions.function();
178c28bcbdfSIngo Weinhold}
179c28bcbdfSIngo Weinhold
180c28bcbdfSIngo Weinhold
181c28bcbdfSIngo Weinholdstatic void
182c28bcbdfSIngo Weinholddo_crash()
183c28bcbdfSIngo Weinhold{
184c28bcbdfSIngo Weinhold	if (sOptions.inSignalHandler) {
185c28bcbdfSIngo Weinhold		signal(SIGUSR1, &signal_handler);
186c28bcbdfSIngo Weinhold		send_signal(find_thread(NULL), SIGUSR1);
187c28bcbdfSIngo Weinhold	} else
188c28bcbdfSIngo Weinhold		sOptions.function();
189c28bcbdfSIngo Weinhold}
190c28bcbdfSIngo Weinhold
191c28bcbdfSIngo Weinhold
192b2537f99SIngo Weinholdstatic status_t
193b2537f99SIngo Weinholdcrashing_thread(void* data)
194b2537f99SIngo Weinhold{
195b2537f99SIngo Weinhold	snooze(100000);
196c28bcbdfSIngo Weinhold	do_crash();
197e9c4d47aSIngo Weinhold	return 0;
198b2537f99SIngo Weinhold}
199b2537f99SIngo Weinhold
200b2537f99SIngo Weinhold
201aff60bb2SIngo Weinholdint
202b2537f99SIngo Weinholdmain(int argc, const char* const* argv)
203aff60bb2SIngo Weinhold{
204b2537f99SIngo Weinhold	const char* mode = "segv";
205aff60bb2SIngo Weinhold
206aff60bb2SIngo Weinhold	// parse args
207aff60bb2SIngo Weinhold	int argi = 1;
208aff60bb2SIngo Weinhold	while (argi < argc) {
209aff60bb2SIngo Weinhold		const char *arg = argv[argi++];
210aff60bb2SIngo Weinhold
211aff60bb2SIngo Weinhold		if (arg[0] == '-') {
212aff60bb2SIngo Weinhold			if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
213aff60bb2SIngo Weinhold				print_usage_and_exit(false);
214e9c4d47aSIngo Weinhold			} else if (strcmp(arg, "-d") == 0) {
215c28bcbdfSIngo Weinhold				sOptions.disableDebugger = true;
21623338ed5SIngo Weinhold			} else if (strcmp(arg, "-f") == 0 || strcmp(arg, "--fork") == 0) {
21723338ed5SIngo Weinhold				sOptions.fork = true;
218180e55a4SIngo Weinhold			} else if (strcmp(arg, "--multi") == 0) {
219180e55a4SIngo Weinhold				sOptions.inThread = true;
220180e55a4SIngo Weinhold				sOptions.multipleThreads = true;
221c28bcbdfSIngo Weinhold			} else if (strcmp(arg, "--signal") == 0) {
222c28bcbdfSIngo Weinhold				sOptions.inSignalHandler = true;
223b2537f99SIngo Weinhold			} else if (strcmp(arg, "--thread") == 0) {
224c28bcbdfSIngo Weinhold				sOptions.inThread = true;
225aff60bb2SIngo Weinhold			} else {
226aff60bb2SIngo Weinhold				fprintf(stderr, "Invalid option \"%s\"\n", arg);
227aff60bb2SIngo Weinhold				print_usage_and_exit(true);
228aff60bb2SIngo Weinhold			}
229aff60bb2SIngo Weinhold		} else {
230aff60bb2SIngo Weinhold			mode = arg;
231aff60bb2SIngo Weinhold		}
232aff60bb2SIngo Weinhold	}
233aff60bb2SIngo Weinhold
234c28bcbdfSIngo Weinhold	sOptions.function = get_crash_function(mode);
235c28bcbdfSIngo Weinhold	if (sOptions.function == NULL) {
236aff60bb2SIngo Weinhold		fprintf(stderr, "Invalid mode \"%s\"\n", mode);
237aff60bb2SIngo Weinhold		print_usage_and_exit(true);
238aff60bb2SIngo Weinhold	}
239aff60bb2SIngo Weinhold
240c28bcbdfSIngo Weinhold	if (sOptions.disableDebugger)
241e9c4d47aSIngo Weinhold		disable_debugger(true);
242e9c4d47aSIngo Weinhold
24323338ed5SIngo Weinhold	if (sOptions.fork) {
24423338ed5SIngo Weinhold		pid_t child = fork();
24523338ed5SIngo Weinhold		if (child < 0) {
24623338ed5SIngo Weinhold			fprintf(stderr, "fork() failed: %s\n", strerror(errno));
24723338ed5SIngo Weinhold			exit(1);
24823338ed5SIngo Weinhold		}
24923338ed5SIngo Weinhold
25023338ed5SIngo Weinhold		if (child > 0) {
25123338ed5SIngo Weinhold			// the parent exits
25223338ed5SIngo Weinhold			exit(1);
25323338ed5SIngo Weinhold		}
25423338ed5SIngo Weinhold
25523338ed5SIngo Weinhold		// the child continues...
25623338ed5SIngo Weinhold	}
25723338ed5SIngo Weinhold
258c28bcbdfSIngo Weinhold	if (sOptions.inThread) {
259b2537f99SIngo Weinhold		thread_id thread = spawn_thread(crashing_thread, "crashing thread",
260c28bcbdfSIngo Weinhold			B_NORMAL_PRIORITY, NULL);
261b2537f99SIngo Weinhold		if (thread < 0) {
262b2537f99SIngo Weinhold			fprintf(stderr, "Error: Failed to spawn thread: %s\n",
263b2537f99SIngo Weinhold				strerror(thread));
264b2537f99SIngo Weinhold			exit(1);
265b2537f99SIngo Weinhold		}
266b2537f99SIngo Weinhold
267b2537f99SIngo Weinhold		resume_thread(thread);
268180e55a4SIngo Weinhold
269180e55a4SIngo Weinhold		if (sOptions.multipleThreads) {
270180e55a4SIngo Weinhold			snooze(200000);
271180e55a4SIngo Weinhold			do_crash();
272180e55a4SIngo Weinhold		} else {
273180e55a4SIngo Weinhold			status_t result;
274180e55a4SIngo Weinhold			while (wait_for_thread(thread, &result) == B_INTERRUPTED) {
275180e55a4SIngo Weinhold			}
276b2537f99SIngo Weinhold		}
277b2537f99SIngo Weinhold	} else {
278c28bcbdfSIngo Weinhold		do_crash();
279b2537f99SIngo Weinhold	}
280b2537f99SIngo Weinhold
281aff60bb2SIngo Weinhold	return 0;
282aff60bb2SIngo Weinhold}