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