libroot_debug: Merge guarded heap into libroot_debug.
[haiku.git] / src / tests / servers / debug / crashing_app.cpp
blob7a30282b2325d86cd1526613129d0b44bfcbbea6
1 /*
2 * Copyright 2005-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #undef NDEBUG
9 #include <assert.h>
10 #include <errno.h>
11 #include <signal.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <unistd.h>
17 #include <OS.h>
19 extern const char *__progname;
21 // usage
22 static const char *kUsage =
23 "%s <options> [ <mode> ]\n"
24 "Crashes in more or less inovative ways.\n"
25 "\n"
26 "Options:\n"
27 " -d - call disable_debugger() first\n"
28 " -f, --fork - fork() and continue in the child\n"
29 " -h, --help - print this info text\n"
30 " --multi - crash in multiple threads\n"
31 " --signal - crash in a signal handler\n"
32 " --thread - crash in a separate thread\n"
33 "\n"
34 "Modes:\n"
35 "[general]\n"
36 " segv - dereferences a null pointer (default)\n"
37 " segv2 - strcmp() using a 0x1 pointer\n"
38 " div - executes a division by zero\n"
39 " debugger - invokes debugger()\n"
40 " assert - failed assert(), which should invoke the\n"
41 " debugger\n"
42 "\n"
43 "[x86 specific]\n"
44 " int3 - executes the int3 (breakpoint) instruction\n"
45 " protection - executes an instruction that causes a general\n"
46 " protection exception\n";
48 // application name
49 const char *kAppName = __progname;
51 static void
52 print_usage(bool error)
54 fprintf(error ? stderr : stdout, kUsage, kAppName);
58 static void
59 print_usage_and_exit(bool error)
61 print_usage(error);
62 exit(error ? 0 : 1);
66 static int
67 crash_segv()
69 int *a = 0;
70 *a = 0;
71 return 0;
74 static int
75 crash_segv2()
77 const char *str = (const char*)0x1;
78 return strcmp(str, "Test");
81 static int
82 crash_div()
84 int i = 0;
85 i = 1 / i;
86 return i;
89 static int
90 crash_debugger()
92 debugger("crashing_app() invoked debugger()");
93 return 0;
97 static int
98 crash_assert()
100 assert(0 > 1);
101 return 0;
105 #if __INTEL__
107 static int
108 crash_int3()
110 asm("int3");
111 return 0;
114 static int
115 crash_protection()
117 asm("movl %0, %%dr7" : : "r"(0));
118 return 0;
121 #endif // __INTEL__
124 typedef int crash_function_t();
127 struct Options {
128 Options()
130 inThread(false),
131 multipleThreads(false),
132 inSignalHandler(false),
133 disableDebugger(false),
134 fork(false)
138 crash_function_t* function;
139 bool inThread;
140 bool multipleThreads;
141 bool inSignalHandler;
142 bool disableDebugger;
143 bool fork;
146 static Options sOptions;
149 static crash_function_t*
150 get_crash_function(const char* mode)
152 if (strcmp(mode, "segv") == 0) {
153 return crash_segv;
154 } else if (strcmp(mode, "segv2") == 0) {
155 return crash_segv2;
156 } else if (strcmp(mode, "div") == 0) {
157 return (crash_function_t*)crash_div;
158 } else if (strcmp(mode, "debugger") == 0) {
159 return crash_debugger;
160 } else if (strcmp(mode, "assert") == 0) {
161 return crash_assert;
162 #if __INTEL__
163 } else if (strcmp(mode, "int3") == 0) {
164 return crash_int3;
165 } else if (strcmp(mode, "protection") == 0) {
166 return crash_protection;
167 #endif // __INTEL__
170 return NULL;
174 static void
175 signal_handler(int signal)
177 sOptions.function();
181 static void
182 do_crash()
184 if (sOptions.inSignalHandler) {
185 signal(SIGUSR1, &signal_handler);
186 send_signal(find_thread(NULL), SIGUSR1);
187 } else
188 sOptions.function();
192 static status_t
193 crashing_thread(void* data)
195 snooze(100000);
196 do_crash();
197 return 0;
202 main(int argc, const char* const* argv)
204 const char* mode = "segv";
206 // parse args
207 int argi = 1;
208 while (argi < argc) {
209 const char *arg = argv[argi++];
211 if (arg[0] == '-') {
212 if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
213 print_usage_and_exit(false);
214 } else if (strcmp(arg, "-d") == 0) {
215 sOptions.disableDebugger = true;
216 } else if (strcmp(arg, "-f") == 0 || strcmp(arg, "--fork") == 0) {
217 sOptions.fork = true;
218 } else if (strcmp(arg, "--multi") == 0) {
219 sOptions.inThread = true;
220 sOptions.multipleThreads = true;
221 } else if (strcmp(arg, "--signal") == 0) {
222 sOptions.inSignalHandler = true;
223 } else if (strcmp(arg, "--thread") == 0) {
224 sOptions.inThread = true;
225 } else {
226 fprintf(stderr, "Invalid option \"%s\"\n", arg);
227 print_usage_and_exit(true);
229 } else {
230 mode = arg;
234 sOptions.function = get_crash_function(mode);
235 if (sOptions.function == NULL) {
236 fprintf(stderr, "Invalid mode \"%s\"\n", mode);
237 print_usage_and_exit(true);
240 if (sOptions.disableDebugger)
241 disable_debugger(true);
243 if (sOptions.fork) {
244 pid_t child = fork();
245 if (child < 0) {
246 fprintf(stderr, "fork() failed: %s\n", strerror(errno));
247 exit(1);
250 if (child > 0) {
251 // the parent exits
252 exit(1);
255 // the child continues...
258 if (sOptions.inThread) {
259 thread_id thread = spawn_thread(crashing_thread, "crashing thread",
260 B_NORMAL_PRIORITY, NULL);
261 if (thread < 0) {
262 fprintf(stderr, "Error: Failed to spawn thread: %s\n",
263 strerror(thread));
264 exit(1);
267 resume_thread(thread);
269 if (sOptions.multipleThreads) {
270 snooze(200000);
271 do_crash();
272 } else {
273 status_t result;
274 while (wait_for_thread(thread, &result) == B_INTERRUPTED) {
277 } else {
278 do_crash();
281 return 0;