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