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