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