xref: /haiku/src/tests/servers/debug/crashing_app.cpp (revision e6b30aee0fd7a23d6a6baab9f3718945a0cd838a)
1 
2 #undef NDEBUG
3 
4 #include <assert.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 
9 #include <OS.h>
10 
11 extern const char *__progname;
12 
13 // usage
14 static const char *kUsage =
15 	"%s <options> [ <mode> ]\n"
16 	"Crashes in more or less inovative ways.\n"
17 	"\n"
18 	"Options:\n"
19 	"  -h, --help           - print this info text\n"
20 	"  --thread             - crash in a separate thread\n"
21 	"\n"
22 	"Modes:\n"
23 	"[general]\n"
24 	"  segv                 - dereferences a null pointer (default)\n"
25 	"  segv2                - strcmp() using a 0x1 pointer\n"
26 	"  div                  - executes a division by zero\n"
27 	"  debugger             - invokes debugger()\n"
28 	"  assert               - failed assert(), which should invoke the "
29 	"                         debugger\n"
30 	"\n"
31 	"[x86 specific]\n"
32 	"  int3                 - executes the int3 (breakpoint) instruction\n"
33 	"  protection           - executes an instruction that causes a general\n"
34 	"                         protection exception\n";
35 
36 // application name
37 const char *kAppName = __progname;
38 
39 static void
40 print_usage(bool error)
41 {
42 	fprintf(error ? stderr : stdout, kUsage, kAppName);
43 }
44 
45 
46 static void
47 print_usage_and_exit(bool error)
48 {
49 	print_usage(error);
50 	exit(error ? 0 : 1);
51 }
52 
53 
54 static int
55 crash_segv()
56 {
57 	int *a = 0;
58 	*a = 0;
59 	return 0;
60 }
61 
62 static int
63 crash_segv2()
64 {
65 	const char *str = (const char*)0x1;
66 	return strcmp(str, "Test");
67 }
68 
69 static int
70 crash_div()
71 {
72 	int i = 0;
73 	i = 1 / i;
74 	return i;
75 }
76 
77 static int
78 crash_debugger()
79 {
80 	debugger("crashing_app() invoked debugger()");
81 	return 0;
82 }
83 
84 
85 static int
86 crash_assert()
87 {
88 	assert(0 > 1);
89 	return 0;
90 }
91 
92 
93 #if __INTEL__
94 
95 static int
96 crash_int3()
97 {
98 	asm("int3");
99 	return 0;
100 }
101 
102 static int
103 crash_protection()
104 {
105 	asm("movl %0, %%dr7" : : "r"(0));
106 	return 0;
107 }
108 
109 #endif	// __INTEL__
110 
111 
112 typedef int crash_function_t();
113 
114 
115 static crash_function_t*
116 get_crash_function(const char* mode)
117 {
118 	if (strcmp(mode, "segv") == 0) {
119 		return crash_segv;
120 	} else if (strcmp(mode, "segv2") == 0) {
121 		return crash_segv2;
122 	} else if (strcmp(mode, "div") == 0) {
123 		return (crash_function_t*)crash_div;
124 	} else if (strcmp(mode, "debugger") == 0) {
125 		return crash_debugger;
126 	} else if (strcmp(mode, "assert") == 0) {
127 		return crash_assert;
128 #if __INTEL__
129 	} else if (strcmp(mode, "int3") == 0) {
130 		return crash_int3;
131 	} else if (strcmp(mode, "protection") == 0) {
132 		return crash_protection;
133 #endif	// __INTEL__
134 	}
135 
136 	return NULL;
137 }
138 
139 
140 static status_t
141 crashing_thread(void* data)
142 {
143 	crash_function_t* doCrash = (crash_function_t*)data;
144 	snooze(100000);
145 	doCrash();
146 }
147 
148 
149 int
150 main(int argc, const char* const* argv)
151 {
152 	bool inThread = false;
153 	const char* mode = "segv";
154 
155 	// parse args
156 	int argi = 1;
157 	while (argi < argc) {
158 		const char *arg = argv[argi++];
159 
160 		if (arg[0] == '-') {
161 			if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
162 				print_usage_and_exit(false);
163 			} else if (strcmp(arg, "--thread") == 0) {
164 				inThread = true;
165 			} else {
166 				fprintf(stderr, "Invalid option \"%s\"\n", arg);
167 				print_usage_and_exit(true);
168 			}
169 		} else {
170 			mode = arg;
171 		}
172 	}
173 
174 	crash_function_t* doCrash = get_crash_function(mode);
175 	if (doCrash == NULL) {
176 		fprintf(stderr, "Invalid mode \"%s\"\n", mode);
177 		print_usage_and_exit(true);
178 	}
179 
180 	if (inThread) {
181 		thread_id thread = spawn_thread(crashing_thread, "crashing thread",
182 			B_NORMAL_PRIORITY, (void*)doCrash);
183 		if (thread < 0) {
184 			fprintf(stderr, "Error: Failed to spawn thread: %s\n",
185 				strerror(thread));
186 			exit(1);
187 		}
188 
189 		resume_thread(thread);
190 		status_t result;
191 		while (wait_for_thread(thread, &result) == B_INTERRUPTED) {
192 		}
193 	} else {
194 		doCrash();
195 	}
196 
197 	return 0;
198 }
199