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
print_pid()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
print_thread_id()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
signal_handler(int signo)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
swap_chars()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
hello()188 static void hello() {
189 std::lock_guard<std::mutex> lock(g_print_mutex);
190 printf("hello, world\n");
191 }
192
thread_func(void * arg)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
main(int argc,char ** argv)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