1/* 2 * Copyright 2005-2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7#undef NDEBUG 8 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> 16 17#include <OS.h> 18 19extern const char *__progname; 20 21// usage 22static 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"; 47 48// application name 49const char *kAppName = __progname; 50 51static void 52print_usage(bool error) 53{ 54 fprintf(error ? stderr : stdout, kUsage, kAppName); 55} 56 57 58static void 59print_usage_and_exit(bool error) 60{ 61 print_usage(error); 62 exit(error ? 0 : 1); 63} 64 65 66static int 67crash_segv() 68{ 69 int *a = 0; 70 *a = 0; 71 return 0; 72} 73 74static int 75crash_segv2() 76{ 77 const char *str = (const char*)0x1; 78 return strcmp(str, "Test"); 79} 80 81static int 82crash_div() 83{ 84 int i = 0; 85 i = 1 / i; 86 return i; 87} 88 89static int 90crash_debugger() 91{ 92 debugger("crashing_app() invoked debugger()"); 93 return 0; 94} 95 96 97static int 98crash_assert() 99{ 100 assert(0 > 1); 101 return 0; 102} 103 104 105#if __INTEL__ 106 107static int 108crash_int3() 109{ 110 asm("int3"); 111 return 0; 112} 113 114static int 115crash_protection() 116{ 117 asm("movl %0, %%dr7" : : "r"(0)); 118 return 0; 119} 120 121#endif // __INTEL__ 122 123 124typedef int crash_function_t(); 125 126 127struct Options { 128 Options() 129 : 130 inThread(false), 131 multipleThreads(false), 132 inSignalHandler(false), 133 disableDebugger(false), 134 fork(false) 135 { 136 } 137 138 crash_function_t* function; 139 bool inThread; 140 bool multipleThreads; 141 bool inSignalHandler; 142 bool disableDebugger; 143 bool fork; 144}; 145 146static Options sOptions; 147 148 149static crash_function_t* 150get_crash_function(const char* mode) 151{ 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__ 168 } 169 170 return NULL; 171} 172 173 174static void 175signal_handler(int signal) 176{ 177 sOptions.function(); 178} 179 180 181static void 182do_crash() 183{ 184 if (sOptions.inSignalHandler) { 185 signal(SIGUSR1, &signal_handler); 186 send_signal(find_thread(NULL), SIGUSR1); 187 } else 188 sOptions.function(); 189} 190 191 192static status_t 193crashing_thread(void* data) 194{ 195 snooze(100000); 196 do_crash(); 197 return 0; 198} 199 200 201int 202main(int argc, const char* const* argv) 203{ 204 const char* mode = "segv"; 205 206 // parse args 207 int argi = 1; 208 while (argi < argc) { 209 const char *arg = argv[argi++]; 210 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); 228 } 229 } else { 230 mode = arg; 231 } 232 } 233 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); 238 } 239 240 if (sOptions.disableDebugger) 241 disable_debugger(true); 242 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); 248 } 249 250 if (child > 0) { 251 // the parent exits 252 exit(1); 253 } 254 255 // the child continues... 256 } 257 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); 265 } 266 267 resume_thread(thread); 268 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) { 275 } 276 } 277 } else { 278 do_crash(); 279 } 280 281 return 0; 282} 283