[Lldb-commits] [lldb] r280675 - remove dependence of TestGdbRemoteExitCode.py on parent directory source

Todd Fiala via lldb-commits lldb-commits at lists.llvm.org
Mon Sep 5 15:03:03 PDT 2016


Author: tfiala
Date: Mon Sep  5 17:03:02 2016
New Revision: 280675

URL: http://llvm.org/viewvc/llvm-project?rev=280675&view=rev
Log:
remove dependence of TestGdbRemoteExitCode.py on parent directory source

As Pavel pointed out in a comment on llvm.org/pr30271, the VPATH I was
using here to eliminate duplication of a .cpp file had a side effect of
attempting to pull in a .o/.obj file from that same parent dir, where
other tests can be running in parallel.  This is no good.

For now, I have removed the VPATH, which should address
llvm.org/pr30271.  I have also removed the XFAIL.

Added:
    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/exit-code/main.cpp
Modified:
    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/exit-code/Makefile
    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/exit-code/TestGdbRemoteExitCode.py

Modified: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/exit-code/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/exit-code/Makefile?rev=280675&r1=280674&r2=280675&view=diff
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/exit-code/Makefile (original)
+++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/exit-code/Makefile Mon Sep  5 17:03:02 2016
@@ -1,7 +1,5 @@
 LEVEL = ../../../make
 
-VPATH = ..
-
 override CFLAGS_EXTRAS += -D__STDC_LIMIT_MACROS -D__STDC_FORMAT_MACROS
 ENABLE_THREADS := YES
 CXX_SOURCES := main.cpp

Modified: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/exit-code/TestGdbRemoteExitCode.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/exit-code/TestGdbRemoteExitCode.py?rev=280675&r1=280674&r2=280675&view=diff
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/exit-code/TestGdbRemoteExitCode.py (original)
+++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/exit-code/TestGdbRemoteExitCode.py Mon Sep  5 17:03:02 2016
@@ -59,7 +59,6 @@ class TestGdbRemoteExitCode(GdbRemoteTes
         self.start_inferior()
 
     @llgs_test
-    @expectedFailureAll(bugnumber="llvm.org/pr30271")
     def test_start_inferior_llgs(self):
         self.init_llgs_test()
         self.build()
@@ -119,7 +118,6 @@ class TestGdbRemoteExitCode(GdbRemoteTes
         self.inferior_exit_42()
 
     @llgs_test
-    @expectedFailureAll(bugnumber="llvm.org/pr30271")
     def test_inferior_exit_42_llgs(self):
         self.init_llgs_test()
         self.build()

Added: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/exit-code/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/exit-code/main.cpp?rev=280675&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/exit-code/main.cpp (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/exit-code/main.cpp Mon Sep  5 17:03:02 2016
@@ -0,0 +1,391 @@
+#include <cstdlib>
+#include <cstring>
+#include <errno.h>
+#include <inttypes.h>
+#include <memory>
+#include <pthread.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <vector>
+
+#if defined(__APPLE__)
+__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2)
+int pthread_threadid_np(pthread_t,__uint64_t*);
+#elif defined(__linux__)
+#include <sys/syscall.h>
+#endif
+
+static const char *const RETVAL_PREFIX               = "retval:";
+static const char *const SLEEP_PREFIX                = "sleep:";
+static const char *const STDERR_PREFIX               = "stderr:";
+static const char *const SET_MESSAGE_PREFIX          = "set-message:";
+static const char *const PRINT_MESSAGE_COMMAND       = "print-message:";
+static const char *const GET_DATA_ADDRESS_PREFIX     = "get-data-address-hex:";
+static const char *const GET_STACK_ADDRESS_COMMAND   = "get-stack-address-hex:";
+static const char *const GET_HEAP_ADDRESS_COMMAND    = "get-heap-address-hex:";
+
+static const char *const GET_CODE_ADDRESS_PREFIX     = "get-code-address-hex:";
+static const char *const CALL_FUNCTION_PREFIX        = "call-function:";
+
+static const char *const THREAD_PREFIX = "thread:";
+static const char *const THREAD_COMMAND_NEW = "new";
+static const char *const THREAD_COMMAND_PRINT_IDS = "print-ids";
+static const char *const THREAD_COMMAND_SEGFAULT = "segfault";
+
+static bool g_print_thread_ids = false;
+static pthread_mutex_t g_print_mutex = PTHREAD_MUTEX_INITIALIZER;
+static bool g_threads_do_segfault = false;
+
+static pthread_mutex_t g_jump_buffer_mutex = PTHREAD_MUTEX_INITIALIZER;
+static jmp_buf g_jump_buffer;
+static bool g_is_segfaulting = false;
+
+static char g_message[256];
+
+static volatile char g_c1 = '0';
+static volatile char g_c2 = '1';
+
+static void
+print_thread_id ()
+{
+	// Put in the right magic here for your platform to spit out the thread id (tid) that debugserver/lldb-gdbserver would see as a TID.
+	// Otherwise, let the else clause print out the unsupported text so that the unit test knows to skip verifying thread ids.
+#if defined(__APPLE__)
+	__uint64_t tid = 0;
+	pthread_threadid_np(pthread_self(), &tid);
+	printf ("%" PRIx64, tid);
+#elif defined (__linux__)
+	// This is a call to gettid() via syscall.
+	printf ("%" PRIx64, static_cast<uint64_t> (syscall (__NR_gettid)));
+#else
+	printf("{no-tid-support}");
+#endif
+}
+
+static void
+signal_handler (int signo)
+{
+	const char *signal_name = nullptr;
+	switch (signo)
+	{
+		case SIGUSR1: signal_name = "SIGUSR1"; break;
+		case SIGSEGV: signal_name = "SIGSEGV"; break;
+		default:      signal_name = nullptr;
+	}
+
+	// Print notice that we received the signal on a given thread.
+	pthread_mutex_lock (&g_print_mutex);
+	if (signal_name)
+		printf ("received %s on thread id: ", signal_name);
+	else
+		printf ("received signo %d (%s) on thread id: ", signo, strsignal (signo));
+	print_thread_id ();
+	printf ("\n");
+	pthread_mutex_unlock (&g_print_mutex);
+
+	// Reset the signal handler if we're one of the expected signal handlers.
+	switch (signo)
+	{
+        case SIGSEGV:
+	        if (g_is_segfaulting)
+	        {
+	            // Fix up the pointer we're writing to.  This needs to happen if nothing intercepts the SIGSEGV
+	            // (i.e. if somebody runs this from the command line).
+	            longjmp(g_jump_buffer, 1);
+			}
+            break;
+        case SIGUSR1:
+            if (g_is_segfaulting)
+            {
+                // Fix up the pointer we're writing to.  This is used to test gdb remote signal delivery.
+                // A SIGSEGV will be raised when the thread is created, switched out for a SIGUSR1, and
+                // then this code still needs to fix the seg fault.
+                // (i.e. if somebody runs this from the command line).
+                longjmp(g_jump_buffer, 1);
+            }
+            break;
+	}
+
+	// Reset the signal handler.
+	sig_t sig_result = signal (signo, signal_handler);
+	if (sig_result == SIG_ERR)
+	{
+		fprintf(stderr, "failed to set signal handler: errno=%d\n", errno);
+		exit (1);
+	}
+}
+
+static void
+swap_chars ()
+{
+    g_c1 = '1';
+    g_c2 = '0';
+
+    g_c1 = '0';
+    g_c2 = '1';
+}
+
+static void
+hello ()
+{
+    pthread_mutex_lock (&g_print_mutex);
+    printf ("hello, world\n");
+    pthread_mutex_unlock (&g_print_mutex);
+}
+
+static void*
+thread_func (void *arg)
+{
+	static pthread_mutex_t s_thread_index_mutex = PTHREAD_MUTEX_INITIALIZER;
+	static int s_thread_index = 1;
+
+	pthread_mutex_lock (&s_thread_index_mutex);
+	const int this_thread_index = s_thread_index++;
+	pthread_mutex_unlock (&s_thread_index_mutex);
+
+	if (g_print_thread_ids)
+	{
+		pthread_mutex_lock (&g_print_mutex);
+		printf ("thread %d id: ", this_thread_index);
+		print_thread_id ();
+		printf ("\n");
+		pthread_mutex_unlock (&g_print_mutex);
+	}
+
+	if (g_threads_do_segfault)
+	{
+		// Sleep for a number of seconds based on the thread index.
+		// TODO add ability to send commands to test exe so we can
+		// handle timing more precisely.  This is clunky.  All we're
+		// trying to do is add predictability as to the timing of
+		// signal generation by created threads.
+		int sleep_seconds = 2 * (this_thread_index - 1);
+		while (sleep_seconds > 0)
+			sleep_seconds = sleep(sleep_seconds);
+
+		// Test creating a SEGV.
+		pthread_mutex_lock (&g_jump_buffer_mutex);
+		g_is_segfaulting = true;
+		int *bad_p = nullptr;
+		if (setjmp(g_jump_buffer) == 0)
+		{
+			// Force a seg fault signal on this thread.
+			*bad_p = 0;
+		}
+		else
+		{
+			// Tell the system we're no longer seg faulting.
+			// Used by the SIGUSR1 signal handler that we inject
+			// in place of the SIGSEGV so it only tries to
+			// recover from the SIGSEGV if this seg fault code
+			// was in play.
+			g_is_segfaulting = false;
+		}
+		pthread_mutex_unlock (&g_jump_buffer_mutex);
+
+		pthread_mutex_lock (&g_print_mutex);
+		printf ("thread ");
+		print_thread_id ();
+		printf (": past SIGSEGV\n");
+		pthread_mutex_unlock (&g_print_mutex);
+	}
+
+	int sleep_seconds_remaining = 60;
+	while (sleep_seconds_remaining > 0)
+	{
+		sleep_seconds_remaining = sleep (sleep_seconds_remaining);
+	}
+
+	return nullptr;
+}
+
+int main (int argc, char **argv)
+{
+	lldb_enable_attach();
+
+	std::vector<pthread_t> threads;
+	std::unique_ptr<uint8_t[]> heap_array_up;
+    int return_value = 0;
+
+	// Set the signal handler.
+	sig_t sig_result = signal (SIGALRM, signal_handler);
+	if (sig_result == SIG_ERR)
+	{
+		fprintf(stderr, "failed to set SIGALRM signal handler: errno=%d\n", errno);
+		exit (1);
+	}
+
+	sig_result = signal (SIGUSR1, signal_handler);
+	if (sig_result == SIG_ERR)
+	{
+		fprintf(stderr, "failed to set SIGUSR1 handler: errno=%d\n", errno);
+		exit (1);
+	}
+
+	sig_result = signal (SIGSEGV, signal_handler);
+	if (sig_result == SIG_ERR)
+	{
+		fprintf(stderr, "failed to set SIGUSR1 handler: errno=%d\n", errno);
+		exit (1);
+	}
+
+	// Process command line args.
+    for (int i = 1; i < argc; ++i)
+    {
+        if (std::strstr (argv[i], STDERR_PREFIX))
+        {
+            // Treat remainder as text to go to stderr.
+            fprintf (stderr, "%s\n", (argv[i] + strlen (STDERR_PREFIX)));
+        }
+        else if (std::strstr (argv[i], RETVAL_PREFIX))
+        {
+            // Treat as the return value for the program.
+            return_value = std::atoi (argv[i] + strlen (RETVAL_PREFIX));
+        }
+        else if (std::strstr (argv[i], SLEEP_PREFIX))
+        {
+            // Treat as the amount of time to have this process sleep (in seconds).
+            int sleep_seconds_remaining = std::atoi (argv[i] + strlen (SLEEP_PREFIX));
+
+			// Loop around, sleeping until all sleep time is used up.  Note that
+			// signals will cause sleep to end early with the number of seconds remaining.
+			for (int i = 0; sleep_seconds_remaining > 0; ++i)
+			{
+				sleep_seconds_remaining = sleep (sleep_seconds_remaining);
+				// std::cout << "sleep result (call " << i << "): " << sleep_seconds_remaining << std::endl;
+			}
+        }
+		else if (std::strstr (argv[i], SET_MESSAGE_PREFIX))
+		{
+			// Copy the contents after "set-message:" to the g_message buffer.
+			// Used for reading inferior memory and verifying contents match expectations.
+            strncpy (g_message, argv[i] + strlen (SET_MESSAGE_PREFIX), sizeof (g_message));
+
+			// Ensure we're null terminated.
+			g_message[sizeof (g_message) - 1] = '\0';
+
+		}
+		else if (std::strstr (argv[i], PRINT_MESSAGE_COMMAND))
+		{
+			pthread_mutex_lock (&g_print_mutex);
+            printf ("message: %s\n", g_message);
+			pthread_mutex_unlock (&g_print_mutex);
+		}
+        else if (std::strstr (argv[i], GET_DATA_ADDRESS_PREFIX))
+        {
+            volatile void *data_p = nullptr;
+
+            if (std::strstr (argv[i] + strlen (GET_DATA_ADDRESS_PREFIX), "g_message"))
+                data_p = &g_message[0];
+            else if (std::strstr (argv[i] + strlen (GET_DATA_ADDRESS_PREFIX), "g_c1"))
+                data_p = &g_c1;
+            else if (std::strstr (argv[i] + strlen (GET_DATA_ADDRESS_PREFIX), "g_c2"))
+                data_p = &g_c2;
+
+			pthread_mutex_lock (&g_print_mutex);
+            printf ("data address: %p\n", data_p);
+			pthread_mutex_unlock (&g_print_mutex);
+        }
+        else if (std::strstr (argv[i], GET_HEAP_ADDRESS_COMMAND))
+        {
+			// Create a byte array if not already present.
+			if (!heap_array_up)
+				heap_array_up.reset (new uint8_t[32]);
+
+			pthread_mutex_lock (&g_print_mutex);
+            printf ("heap address: %p\n", heap_array_up.get ());
+			pthread_mutex_unlock (&g_print_mutex);
+        }
+        else if (std::strstr (argv[i], GET_STACK_ADDRESS_COMMAND))
+        {
+			pthread_mutex_lock (&g_print_mutex);
+            printf ("stack address: %p\n", &return_value);
+			pthread_mutex_unlock (&g_print_mutex);
+        }
+        else if (std::strstr (argv[i], GET_CODE_ADDRESS_PREFIX))
+        {
+            void (*func_p)() = nullptr;
+
+            if (std::strstr (argv[i] + strlen (GET_CODE_ADDRESS_PREFIX), "hello"))
+                func_p = hello;
+            else if (std::strstr (argv[i] + strlen (GET_CODE_ADDRESS_PREFIX), "swap_chars"))
+                func_p = swap_chars;
+
+			pthread_mutex_lock (&g_print_mutex);
+            printf ("code address: %p\n", func_p);
+			pthread_mutex_unlock (&g_print_mutex);
+        }
+        else if (std::strstr (argv[i], CALL_FUNCTION_PREFIX))
+        {
+            // Defaut to providing the address of main.
+            if (std::strcmp (argv[i] + strlen (CALL_FUNCTION_PREFIX), "hello") == 0)
+                hello();
+            else if (std::strcmp (argv[i] + strlen (CALL_FUNCTION_PREFIX), "swap_chars") == 0)
+                swap_chars();
+            else
+            {
+                pthread_mutex_lock (&g_print_mutex);
+                printf ("unknown function: %s\n", argv[i] + strlen (CALL_FUNCTION_PREFIX));
+                pthread_mutex_unlock (&g_print_mutex);
+            }
+        }
+		else if (std::strstr (argv[i], THREAD_PREFIX))
+		{
+			// Check if we're creating a new thread.
+			if (std::strstr (argv[i] + strlen(THREAD_PREFIX), THREAD_COMMAND_NEW))
+			{
+				// Create a new thread.
+				pthread_t new_thread;
+				const int err = ::pthread_create (&new_thread, nullptr, thread_func, nullptr);
+			    if (err)
+				{
+					fprintf (stderr, "pthread_create() failed with error code %d\n", err);
+					exit (err);
+				}
+				threads.push_back (new_thread);
+			}
+			else if (std::strstr (argv[i] + strlen(THREAD_PREFIX), THREAD_COMMAND_PRINT_IDS))
+			{
+				// Turn on thread id announcing.
+				g_print_thread_ids = true;
+
+				// And announce us.
+				pthread_mutex_lock (&g_print_mutex);
+				printf ("thread 0 id: ");
+				print_thread_id ();
+				printf ("\n");
+				pthread_mutex_unlock (&g_print_mutex);
+			}
+			else if (std::strstr (argv[i] + strlen(THREAD_PREFIX), THREAD_COMMAND_SEGFAULT))
+			{
+				g_threads_do_segfault = true;
+			}
+			else
+			{
+				// At this point we don't do anything else with threads.
+				// Later use thread index and send command to thread.
+			}
+		}
+        else
+        {
+            // Treat the argument as text for stdout.
+            printf("%s\n", argv[i]);
+        }
+    }
+
+	// If we launched any threads, join them
+	for (std::vector<pthread_t>::iterator it = threads.begin (); it != threads.end (); ++it)
+	{
+		void *thread_retval = nullptr;
+		const int err = ::pthread_join (*it, &thread_retval);
+	    if (err != 0)
+			fprintf (stderr, "pthread_join() failed with error code %d\n", err);
+	}
+    
+    return return_value;
+}




More information about the lldb-commits mailing list