1 #include <atomic> 2 #include <chrono> 3 #include <cstdlib> 4 #include <cstring> 5 #include <errno.h> 6 #include <inttypes.h> 7 #include <memory> 8 #include <mutex> 9 #if !defined(_WIN32) 10 #include <pthread.h> 11 #include <signal.h> 12 #include <unistd.h> 13 #endif 14 #include "thread.h" 15 #include <setjmp.h> 16 #include <stdint.h> 17 #include <stdio.h> 18 #include <string.h> 19 #include <string> 20 #include <thread> 21 #include <time.h> 22 #include <vector> 23 #if defined(__APPLE__) 24 #include <TargetConditionals.h> 25 #endif 26 27 static const char *const PRINT_PID_COMMAND = "print-pid"; 28 29 static bool g_print_thread_ids = false; 30 static std::mutex g_print_mutex; 31 static bool g_threads_do_segfault = false; 32 33 static std::mutex g_jump_buffer_mutex; 34 static jmp_buf g_jump_buffer; 35 static bool g_is_segfaulting = false; 36 37 static char g_message[256]; 38 39 static volatile char g_c1 = '0'; 40 static volatile char g_c2 = '1'; 41 42 static void print_pid() { 43 #if defined(_WIN32) 44 fprintf(stderr, "PID: %d\n", ::GetCurrentProcessId()); 45 #else 46 fprintf(stderr, "PID: %d\n", getpid()); 47 #endif 48 } 49 50 static void signal_handler(int signo) { 51 #if defined(_WIN32) 52 // No signal support on Windows. 53 #else 54 const char *signal_name = nullptr; 55 switch (signo) { 56 case SIGUSR1: 57 signal_name = "SIGUSR1"; 58 break; 59 case SIGSEGV: 60 signal_name = "SIGSEGV"; 61 break; 62 default: 63 signal_name = nullptr; 64 } 65 66 // Print notice that we received the signal on a given thread. 67 char buf[100]; 68 if (signal_name) 69 snprintf(buf, sizeof(buf), "received %s on thread id: %" PRIx64 "\n", signal_name, get_thread_id()); 70 else 71 snprintf(buf, sizeof(buf), "received signo %d (%s) on thread id: %" PRIx64 "\n", signo, strsignal(signo), get_thread_id()); 72 write(STDOUT_FILENO, buf, strlen(buf)); 73 74 // Reset the signal handler if we're one of the expected signal handlers. 75 switch (signo) { 76 case SIGSEGV: 77 if (g_is_segfaulting) { 78 // Fix up the pointer we're writing to. This needs to happen if nothing 79 // intercepts the SIGSEGV (i.e. if somebody runs this from the command 80 // line). 81 longjmp(g_jump_buffer, 1); 82 } 83 break; 84 case SIGUSR1: 85 if (g_is_segfaulting) { 86 // Fix up the pointer we're writing to. This is used to test gdb remote 87 // signal delivery. A SIGSEGV will be raised when the thread is created, 88 // switched out for a SIGUSR1, and then this code still needs to fix the 89 // seg fault. (i.e. if somebody runs this from the command line). 90 longjmp(g_jump_buffer, 1); 91 } 92 break; 93 } 94 95 // Reset the signal handler. 96 sig_t sig_result = signal(signo, signal_handler); 97 if (sig_result == SIG_ERR) { 98 fprintf(stderr, "failed to set signal handler: errno=%d\n", errno); 99 exit(1); 100 } 101 #endif 102 } 103 104 static void swap_chars() { 105 #if defined(__x86_64__) || defined(__i386__) 106 asm volatile("movb %1, (%2)\n\t" 107 "movb %0, (%3)\n\t" 108 "movb %0, (%2)\n\t" 109 "movb %1, (%3)\n\t" 110 : 111 : "i"('0'), "i"('1'), "r"(&g_c1), "r"(&g_c2) 112 : "memory"); 113 #elif defined(__aarch64__) 114 asm volatile("strb %w1, [%2]\n\t" 115 "strb %w0, [%3]\n\t" 116 "strb %w0, [%2]\n\t" 117 "strb %w1, [%3]\n\t" 118 : 119 : "r"('0'), "r"('1'), "r"(&g_c1), "r"(&g_c2) 120 : "memory"); 121 #elif defined(__arm__) 122 asm volatile("strb %1, [%2]\n\t" 123 "strb %0, [%3]\n\t" 124 "strb %0, [%2]\n\t" 125 "strb %1, [%3]\n\t" 126 : 127 : "r"('0'), "r"('1'), "r"(&g_c1), "r"(&g_c2) 128 : "memory"); 129 #else 130 #warning This may generate unpredictible assembly and cause the single-stepping test to fail. 131 #warning Please add appropriate assembly for your target. 132 g_c1 = '1'; 133 g_c2 = '0'; 134 135 g_c1 = '0'; 136 g_c2 = '1'; 137 #endif 138 } 139 140 static void trap() { 141 #if defined(__x86_64__) || defined(__i386__) 142 asm volatile("int3"); 143 #elif defined(__aarch64__) 144 asm volatile("brk #0xf000"); 145 #elif defined(__arm__) 146 asm volatile("udf #254"); 147 #elif defined(__powerpc__) 148 asm volatile("trap"); 149 #elif __has_builtin(__builtin_debugtrap()) 150 __builtin_debugtrap(); 151 #else 152 #warning Don't know how to generate a trap. Some tests may fail. 153 #endif 154 } 155 156 static void hello() { 157 std::lock_guard<std::mutex> lock(g_print_mutex); 158 printf("hello, world\n"); 159 } 160 161 static void *thread_func(void *arg) { 162 static std::atomic<int> s_thread_index(1); 163 const int this_thread_index = s_thread_index++; 164 if (g_print_thread_ids) { 165 std::lock_guard<std::mutex> lock(g_print_mutex); 166 printf("thread %d id: %" PRIx64 "\n", this_thread_index, get_thread_id()); 167 } 168 169 if (g_threads_do_segfault) { 170 // Sleep for a number of seconds based on the thread index. 171 // TODO add ability to send commands to test exe so we can 172 // handle timing more precisely. This is clunky. All we're 173 // trying to do is add predictability as to the timing of 174 // signal generation by created threads. 175 int sleep_seconds = 2 * (this_thread_index - 1); 176 std::this_thread::sleep_for(std::chrono::seconds(sleep_seconds)); 177 178 // Test creating a SEGV. 179 { 180 std::lock_guard<std::mutex> lock(g_jump_buffer_mutex); 181 g_is_segfaulting = true; 182 int *bad_p = nullptr; 183 if (setjmp(g_jump_buffer) == 0) { 184 // Force a seg fault signal on this thread. 185 *bad_p = 0; 186 } else { 187 // Tell the system we're no longer seg faulting. 188 // Used by the SIGUSR1 signal handler that we inject 189 // in place of the SIGSEGV so it only tries to 190 // recover from the SIGSEGV if this seg fault code 191 // was in play. 192 g_is_segfaulting = false; 193 } 194 } 195 196 { 197 std::lock_guard<std::mutex> lock(g_print_mutex); 198 printf("thread %" PRIx64 ": past SIGSEGV\n", get_thread_id()); 199 } 200 } 201 202 int sleep_seconds_remaining = 60; 203 std::this_thread::sleep_for(std::chrono::seconds(sleep_seconds_remaining)); 204 205 return nullptr; 206 } 207 208 static bool consume_front(std::string &str, const std::string &front) { 209 if (str.find(front) != 0) 210 return false; 211 212 str = str.substr(front.size()); 213 return true; 214 } 215 216 int main(int argc, char **argv) { 217 lldb_enable_attach(); 218 219 std::vector<std::thread> threads; 220 std::unique_ptr<uint8_t[]> heap_array_up; 221 int return_value = 0; 222 223 #if !defined(_WIN32) 224 // Set the signal handler. 225 sig_t sig_result = signal(SIGALRM, signal_handler); 226 if (sig_result == SIG_ERR) { 227 fprintf(stderr, "failed to set SIGALRM signal handler: errno=%d\n", errno); 228 exit(1); 229 } 230 231 sig_result = signal(SIGUSR1, signal_handler); 232 if (sig_result == SIG_ERR) { 233 fprintf(stderr, "failed to set SIGUSR1 handler: errno=%d\n", errno); 234 exit(1); 235 } 236 237 sig_result = signal(SIGSEGV, signal_handler); 238 if (sig_result == SIG_ERR) { 239 fprintf(stderr, "failed to set SIGSEGV handler: errno=%d\n", errno); 240 exit(1); 241 } 242 243 sig_result = signal(SIGCHLD, SIG_IGN); 244 if (sig_result == SIG_ERR) { 245 fprintf(stderr, "failed to set SIGCHLD handler: errno=%d\n", errno); 246 exit(1); 247 } 248 #endif 249 250 // Process command line args. 251 for (int i = 1; i < argc; ++i) { 252 std::string arg = argv[i]; 253 if (consume_front(arg, "stderr:")) { 254 // Treat remainder as text to go to stderr. 255 fprintf(stderr, "%s\n", arg.c_str()); 256 } else if (consume_front(arg, "retval:")) { 257 // Treat as the return value for the program. 258 return_value = std::atoi(arg.c_str()); 259 } else if (consume_front(arg, "sleep:")) { 260 // Treat as the amount of time to have this process sleep (in seconds). 261 int sleep_seconds_remaining = std::atoi(arg.c_str()); 262 263 // Loop around, sleeping until all sleep time is used up. Note that 264 // signals will cause sleep to end early with the number of seconds 265 // remaining. 266 std::this_thread::sleep_for( 267 std::chrono::seconds(sleep_seconds_remaining)); 268 269 } else if (consume_front(arg, "set-message:")) { 270 // Copy the contents after "set-message:" to the g_message buffer. 271 // Used for reading inferior memory and verifying contents match 272 // expectations. 273 strncpy(g_message, arg.c_str(), sizeof(g_message)); 274 275 // Ensure we're null terminated. 276 g_message[sizeof(g_message) - 1] = '\0'; 277 278 } else if (consume_front(arg, "print-message:")) { 279 std::lock_guard<std::mutex> lock(g_print_mutex); 280 printf("message: %s\n", g_message); 281 } else if (consume_front(arg, "get-data-address-hex:")) { 282 volatile void *data_p = nullptr; 283 284 if (arg == "g_message") 285 data_p = &g_message[0]; 286 else if (arg == "g_c1") 287 data_p = &g_c1; 288 else if (arg == "g_c2") 289 data_p = &g_c2; 290 291 std::lock_guard<std::mutex> lock(g_print_mutex); 292 printf("data address: %p\n", data_p); 293 } else if (consume_front(arg, "get-heap-address-hex:")) { 294 // Create a byte array if not already present. 295 if (!heap_array_up) 296 heap_array_up.reset(new uint8_t[32]); 297 298 std::lock_guard<std::mutex> lock(g_print_mutex); 299 printf("heap address: %p\n", heap_array_up.get()); 300 301 } else if (consume_front(arg, "get-stack-address-hex:")) { 302 std::lock_guard<std::mutex> lock(g_print_mutex); 303 printf("stack address: %p\n", &return_value); 304 } else if (consume_front(arg, "get-code-address-hex:")) { 305 void (*func_p)() = nullptr; 306 307 if (arg == "hello") 308 func_p = hello; 309 else if (arg == "swap_chars") 310 func_p = swap_chars; 311 312 std::lock_guard<std::mutex> lock(g_print_mutex); 313 printf("code address: %p\n", func_p); 314 } else if (consume_front(arg, "call-function:")) { 315 void (*func_p)() = nullptr; 316 317 if (arg == "hello") 318 func_p = hello; 319 else if (arg == "swap_chars") 320 func_p = swap_chars; 321 func_p(); 322 #if !defined(_WIN32) && !defined(TARGET_OS_WATCH) && !defined(TARGET_OS_TV) 323 } else if (arg == "fork") { 324 if (fork() == 0) 325 _exit(0); 326 } else if (arg == "vfork") { 327 if (vfork() == 0) 328 _exit(0); 329 #endif 330 } else if (consume_front(arg, "thread:new")) { 331 threads.push_back(std::thread(thread_func, nullptr)); 332 } else if (consume_front(arg, "thread:print-ids")) { 333 // Turn on thread id announcing. 334 g_print_thread_ids = true; 335 336 // And announce us. 337 { 338 std::lock_guard<std::mutex> lock(g_print_mutex); 339 printf("thread 0 id: %" PRIx64 "\n", get_thread_id()); 340 } 341 } else if (consume_front(arg, "thread:segfault")) { 342 g_threads_do_segfault = true; 343 } else if (consume_front(arg, "print-pid")) { 344 print_pid(); 345 } else if (consume_front(arg, "print-env:")) { 346 // Print the value of specified envvar to stdout. 347 const char *value = getenv(arg.c_str()); 348 printf("%s\n", value ? value : "__unset__"); 349 } else if (consume_front(arg, "trap")) { 350 trap(); 351 } else { 352 // Treat the argument as text for stdout. 353 printf("%s\n", argv[i]); 354 } 355 } 356 357 // If we launched any threads, join them 358 for (std::vector<std::thread>::iterator it = threads.begin(); 359 it != threads.end(); ++it) 360 it->join(); 361 362 return return_value; 363 } 364