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 19 extern const char *__progname; 20 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"; 47 48 // application name 49 const char *kAppName = __progname; 50 51 static void 52 print_usage(bool error) 53 { 54 fprintf(error ? stderr : stdout, kUsage, kAppName); 55 } 56 57 58 static void 59 print_usage_and_exit(bool error) 60 { 61 print_usage(error); 62 exit(error ? 0 : 1); 63 } 64 65 66 static int 67 crash_segv() 68 { 69 int *a = 0; 70 *a = 0; 71 return 0; 72 } 73 74 static int 75 crash_segv2() 76 { 77 const char *str = (const char*)0x1; 78 return strcmp(str, "Test"); 79 } 80 81 static int 82 crash_div() 83 { 84 int i = 0; 85 i = 1 / i; 86 return i; 87 } 88 89 static int 90 crash_debugger() 91 { 92 debugger("crashing_app() invoked debugger()"); 93 return 0; 94 } 95 96 97 static int 98 crash_assert() 99 { 100 assert(0 > 1); 101 return 0; 102 } 103 104 105 #if __i386__ 106 107 static int 108 crash_int3() 109 { 110 asm("int3"); 111 return 0; 112 } 113 114 static int 115 crash_protection() 116 { 117 asm("movl %0, %%dr7" : : "r"(0)); 118 return 0; 119 } 120 121 #endif // __i386__ 122 123 124 typedef int crash_function_t(); 125 126 127 struct 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 146 static Options sOptions; 147 148 149 static crash_function_t* 150 get_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 __i386__ 163 } else if (strcmp(mode, "int3") == 0) { 164 return crash_int3; 165 } else if (strcmp(mode, "protection") == 0) { 166 return crash_protection; 167 #endif // __i386__ 168 } 169 170 return NULL; 171 } 172 173 174 static void 175 signal_handler(int signal) 176 { 177 sOptions.function(); 178 } 179 180 181 static void 182 do_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 192 static status_t 193 crashing_thread(void* data) 194 { 195 snooze(100000); 196 do_crash(); 197 return 0; 198 } 199 200 201 int 202 main(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