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 g_c1 = '1'; 154 g_c2 = '0'; 155 156 g_c1 = '0'; 157 g_c2 = '1'; 158 } 159 160 static void hello() { 161 std::lock_guard<std::mutex> lock(g_print_mutex); 162 printf("hello, world\n"); 163 } 164 165 static void *thread_func(void *arg) { 166 static std::atomic<int> s_thread_index(1); 167 const int this_thread_index = s_thread_index++; 168 if (g_print_thread_ids) { 169 std::lock_guard<std::mutex> lock(g_print_mutex); 170 printf("thread %d id: ", this_thread_index); 171 print_thread_id(); 172 printf("\n"); 173 } 174 175 if (g_threads_do_segfault) { 176 // Sleep for a number of seconds based on the thread index. 177 // TODO add ability to send commands to test exe so we can 178 // handle timing more precisely. This is clunky. All we're 179 // trying to do is add predictability as to the timing of 180 // signal generation by created threads. 181 int sleep_seconds = 2 * (this_thread_index - 1); 182 std::this_thread::sleep_for(std::chrono::seconds(sleep_seconds)); 183 184 // Test creating a SEGV. 185 { 186 std::lock_guard<std::mutex> lock(g_jump_buffer_mutex); 187 g_is_segfaulting = true; 188 int *bad_p = nullptr; 189 if (setjmp(g_jump_buffer) == 0) { 190 // Force a seg fault signal on this thread. 191 *bad_p = 0; 192 } else { 193 // Tell the system we're no longer seg faulting. 194 // Used by the SIGUSR1 signal handler that we inject 195 // in place of the SIGSEGV so it only tries to 196 // recover from the SIGSEGV if this seg fault code 197 // was in play. 198 g_is_segfaulting = false; 199 } 200 } 201 202 { 203 std::lock_guard<std::mutex> lock(g_print_mutex); 204 printf("thread "); 205 print_thread_id(); 206 printf(": past SIGSEGV\n"); 207 } 208 } 209 210 int sleep_seconds_remaining = 60; 211 std::this_thread::sleep_for(std::chrono::seconds(sleep_seconds_remaining)); 212 213 return nullptr; 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 SIGUSR1 handler: errno=%d\n", errno); 240 exit(1); 241 } 242 #endif 243 244 // Process command line args. 245 for (int i = 1; i < argc; ++i) { 246 if (std::strstr(argv[i], STDERR_PREFIX)) { 247 // Treat remainder as text to go to stderr. 248 fprintf(stderr, "%s\n", (argv[i] + strlen(STDERR_PREFIX))); 249 } else if (std::strstr(argv[i], RETVAL_PREFIX)) { 250 // Treat as the return value for the program. 251 return_value = std::atoi(argv[i] + strlen(RETVAL_PREFIX)); 252 } else if (std::strstr(argv[i], SLEEP_PREFIX)) { 253 // Treat as the amount of time to have this process sleep (in seconds). 254 int sleep_seconds_remaining = std::atoi(argv[i] + strlen(SLEEP_PREFIX)); 255 256 // Loop around, sleeping until all sleep time is used up. Note that 257 // signals will cause sleep to end early with the number of seconds 258 // remaining. 259 std::this_thread::sleep_for( 260 std::chrono::seconds(sleep_seconds_remaining)); 261 262 } else if (std::strstr(argv[i], SET_MESSAGE_PREFIX)) { 263 // Copy the contents after "set-message:" to the g_message buffer. 264 // Used for reading inferior memory and verifying contents match 265 // expectations. 266 strncpy(g_message, argv[i] + strlen(SET_MESSAGE_PREFIX), 267 sizeof(g_message)); 268 269 // Ensure we're null terminated. 270 g_message[sizeof(g_message) - 1] = '\0'; 271 272 } else if (std::strstr(argv[i], PRINT_MESSAGE_COMMAND)) { 273 std::lock_guard<std::mutex> lock(g_print_mutex); 274 printf("message: %s\n", g_message); 275 } else if (std::strstr(argv[i], GET_DATA_ADDRESS_PREFIX)) { 276 volatile void *data_p = nullptr; 277 278 if (std::strstr(argv[i] + strlen(GET_DATA_ADDRESS_PREFIX), "g_message")) 279 data_p = &g_message[0]; 280 else if (std::strstr(argv[i] + strlen(GET_DATA_ADDRESS_PREFIX), "g_c1")) 281 data_p = &g_c1; 282 else if (std::strstr(argv[i] + strlen(GET_DATA_ADDRESS_PREFIX), "g_c2")) 283 data_p = &g_c2; 284 285 std::lock_guard<std::mutex> lock(g_print_mutex); 286 printf("data address: %p\n", data_p); 287 } else if (std::strstr(argv[i], GET_HEAP_ADDRESS_COMMAND)) { 288 // Create a byte array if not already present. 289 if (!heap_array_up) 290 heap_array_up.reset(new uint8_t[32]); 291 292 std::lock_guard<std::mutex> lock(g_print_mutex); 293 printf("heap address: %p\n", heap_array_up.get()); 294 295 } else if (std::strstr(argv[i], GET_STACK_ADDRESS_COMMAND)) { 296 std::lock_guard<std::mutex> lock(g_print_mutex); 297 printf("stack address: %p\n", &return_value); 298 } else if (std::strstr(argv[i], GET_CODE_ADDRESS_PREFIX)) { 299 void (*func_p)() = nullptr; 300 301 if (std::strstr(argv[i] + strlen(GET_CODE_ADDRESS_PREFIX), "hello")) 302 func_p = hello; 303 else if (std::strstr(argv[i] + strlen(GET_CODE_ADDRESS_PREFIX), 304 "swap_chars")) 305 func_p = swap_chars; 306 307 std::lock_guard<std::mutex> lock(g_print_mutex); 308 printf("code address: %p\n", func_p); 309 } else if (std::strstr(argv[i], CALL_FUNCTION_PREFIX)) { 310 void (*func_p)() = nullptr; 311 312 // Defaut to providing the address of main. 313 if (std::strcmp(argv[i] + strlen(CALL_FUNCTION_PREFIX), "hello") == 0) 314 func_p = hello; 315 else if (std::strcmp(argv[i] + strlen(CALL_FUNCTION_PREFIX), 316 "swap_chars") == 0) 317 func_p = swap_chars; 318 else { 319 std::lock_guard<std::mutex> lock(g_print_mutex); 320 printf("unknown function: %s\n", 321 argv[i] + strlen(CALL_FUNCTION_PREFIX)); 322 } 323 if (func_p) 324 func_p(); 325 } else if (std::strstr(argv[i], THREAD_PREFIX)) { 326 // Check if we're creating a new thread. 327 if (std::strstr(argv[i] + strlen(THREAD_PREFIX), THREAD_COMMAND_NEW)) { 328 threads.push_back(std::thread(thread_func, nullptr)); 329 } else if (std::strstr(argv[i] + strlen(THREAD_PREFIX), 330 THREAD_COMMAND_PRINT_IDS)) { 331 // Turn on thread id announcing. 332 g_print_thread_ids = true; 333 334 // And announce us. 335 { 336 std::lock_guard<std::mutex> lock(g_print_mutex); 337 printf("thread 0 id: "); 338 print_thread_id(); 339 printf("\n"); 340 } 341 } else if (std::strstr(argv[i] + strlen(THREAD_PREFIX), 342 THREAD_COMMAND_SEGFAULT)) { 343 g_threads_do_segfault = true; 344 } else { 345 // At this point we don't do anything else with threads. 346 // Later use thread index and send command to thread. 347 } 348 } else if (std::strstr(argv[i], PRINT_PID_COMMAND)) { 349 print_pid(); 350 } else { 351 // Treat the argument as text for stdout. 352 printf("%s\n", argv[i]); 353 } 354 } 355 356 // If we launched any threads, join them 357 for (std::vector<std::thread>::iterator it = threads.begin(); 358 it != threads.end(); ++it) 359 it->join(); 360 361 return return_value; 362 } 363