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