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