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