[Lldb-commits] [lldb] r210272 - Added gdb-remote test for software breakpoints.

Todd Fiala todd.fiala at gmail.com
Thu Jun 5 09:34:13 PDT 2014


Author: tfiala
Date: Thu Jun  5 11:34:13 2014
New Revision: 210272

URL: http://llvm.org/viewvc/llvm-project?rev=210272&view=rev
Log:
Added gdb-remote test for software breakpoints.

Tests $Z0 and $z0.  Extends test exe get-code-address-hex:
to take a function name.

Enabled for debugserver, disabled for llgs.  Implementing
in llgs branch next.

Modified:
    lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py
    lldb/trunk/test/tools/lldb-gdbserver/main.cpp

Modified: lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py?rev=210272&r1=210271&r2=210272&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py Thu Jun  5 11:34:13 2014
@@ -49,7 +49,7 @@ class LldbGdbServerTestCase(TestBase):
         self.set_inferior_startup_launch()
 
         # Uncomment this code to force only a single test to run (by name).
-        # if not re.search(r"qMemoryRegionInfo", self._testMethodName):
+        # if not re.search(r"breakpoint", self._testMethodName):
         #     self.skipTest("focusing on one test")
 
     def reset_test_sequence(self):
@@ -1351,7 +1351,7 @@ class LldbGdbServerTestCase(TestBase):
     def qMemoryRegionInfo_reports_code_address_as_executable(self):
         # Start up the inferior.
         procs = self.prep_debug_monitor_and_inferior(
-            inferior_args=["get-code-address-hex:", "sleep:5"])
+            inferior_args=["get-code-address-hex:hello", "sleep:5"])
 
         # Run the process
         self.test_sequence.add_log_lines(
@@ -1534,6 +1534,101 @@ class LldbGdbServerTestCase(TestBase):
         self.set_inferior_startup_launch()
         self.qMemoryRegionInfo_reports_heap_address_as_readable_writeable()
 
+    def software_breakpoint_set_and_remove_work(self):
+        # Start up the inferior.
+        procs = self.prep_debug_monitor_and_inferior(
+            inferior_args=["get-code-address-hex:hello", "sleep:1", "call-function:hello"])
+
+        # Run the process
+        self.test_sequence.add_log_lines(
+            [
+             # Start running after initial stop.
+             "read packet: $c#00",
+             # Match output line that prints the memory address of the function call entry point.
+             # Note we require launch-only testing so we can get inferior otuput.
+             { "type":"output_match", "regex":r"^code address: 0x([0-9a-fA-F]+)\r\n$", "capture":{ 1:"function_address"} },
+             # Now stop the inferior.
+             "read packet: {}".format(chr(03)),
+             # And wait for the stop notification.
+             {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} }],
+            True)
+
+        # Run the packet stream.
+        context = self.expect_gdbremote_sequence()
+        self.assertIsNotNone(context)
+
+        # Grab the address.
+        self.assertIsNotNone(context.get("function_address"))
+        function_address = int(context.get("function_address"), 16)
+
+        # Set the breakpoint.
+        # Note this might need to be switched per platform (ARM, mips, etc.).
+        BREAKPOINT_KIND = 1
+        
+        self.reset_test_sequence()
+        self.test_sequence.add_log_lines(
+            [
+             # Set the breakpoint.
+             "read packet: $Z0,{0:x},{1}#00".format(function_address, BREAKPOINT_KIND),
+             # Verify the stub could set it.
+             "send packet: $OK#00",
+             # Continue the inferior.
+             "read packet: $c#00",
+             # Expect a breakpoint stop report.
+             {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} },
+             ], True)
+             
+        # Run the packet stream.
+        context = self.expect_gdbremote_sequence()
+        self.assertIsNotNone(context)
+
+        # Verify the stop signal reported was the breakpoint signal number.
+        stop_signo = context.get("stop_signo")
+        self.assertIsNotNone(stop_signo)
+        self.assertEquals(int(stop_signo,16), signal.SIGTRAP)
+
+        # Ensure we did not receive any output.  If the breakpoint was not set, we would
+        # see output (from a launched process with captured stdio) printing a hello, world message.
+        # That would indicate the breakpoint didn't take.
+        self.assertEquals(len(context["O_content"]), 0)
+
+        # Verify that a breakpoint unset and continue gets us the expected output.
+        self.reset_test_sequence()
+        self.test_sequence.add_log_lines(
+            [
+             # Remove the breakpoint.
+             "read packet: $z0,{0:x},{1}#00".format(function_address, BREAKPOINT_KIND),
+             # Verify the stub could unset it.
+             "send packet: $OK#00",
+             # Continue running.
+             "read packet: $c#00",
+             # We should now receive the output from the call.
+             { "type":"output_match", "regex":r"^hello, world\r\n$" },
+             # And wait for program completion.
+             {"direction":"send", "regex":r"^\$W00(.*)#00" },
+             ], True)
+
+        context = self.expect_gdbremote_sequence()
+        self.assertIsNotNone(context)
+        
+
+    @debugserver_test
+    @dsym_test
+    def test_software_breakpoint_set_and_remove_work_debugserver_dsym(self):
+        self.init_debugserver_test()
+        self.buildDsym()
+        self.set_inferior_startup_launch()
+        self.software_breakpoint_set_and_remove_work()
+
+    @llgs_test
+    @dwarf_test
+    @unittest2.expectedFailure()
+    def test_software_breakpoint_set_and_remove_work_llgs_dwarf(self):
+        self.init_llgs_test()
+        self.buildDwarf()
+        self.set_inferior_startup_launch()
+        self.software_breakpoint_set_and_remove_work()
+
 
 if __name__ == '__main__':
     unittest2.main()

Modified: lldb/trunk/test/tools/lldb-gdbserver/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/main.cpp?rev=210272&r1=210271&r2=210272&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/main.cpp (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/main.cpp Thu Jun  5 11:34:13 2014
@@ -20,14 +20,16 @@ int pthread_threadid_np(pthread_t,__uint
 #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 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 GET_MESSAGE_ADDRESS_COMMAND = "get-message-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_COMMAND = "get-code-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";
@@ -64,12 +66,12 @@ print_thread_id ()
 static void
 signal_handler (int signo)
 {
-	const char *signal_name = NULL;
+	const char *signal_name = nullptr;
 	switch (signo)
 	{
 		case SIGUSR1: signal_name = "SIGUSR1"; break;
 		case SIGSEGV: signal_name = "SIGSEGV"; break;
-		default:      signal_name = NULL;
+		default:      signal_name = nullptr;
 	}
 
 	// Print notice that we received the signal on a given thread.
@@ -111,6 +113,14 @@ signal_handler (int signo)
 	}
 }
 
+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)
 {
@@ -144,7 +154,7 @@ thread_func (void *arg)
 		// Test creating a SEGV.
 		pthread_mutex_lock (&g_jump_buffer_mutex);
 		g_is_segfaulting = true;
-		int *bad_p = NULL;
+		int *bad_p = nullptr;
 		if (setjmp(g_jump_buffer) == 0)
 		{
 			// Force a seg fault signal on this thread.
@@ -174,7 +184,7 @@ thread_func (void *arg)
 		sleep_seconds_remaining = sleep (sleep_seconds_remaining);
 	}
 
-	return NULL;
+	return nullptr;
 }
 
 int main (int argc, char **argv)
@@ -263,12 +273,30 @@ int main (int argc, char **argv)
             printf ("stack address: %p\n", &return_value);
 			pthread_mutex_unlock (&g_print_mutex);
         }
-        else if (std::strstr (argv[i], GET_CODE_ADDRESS_COMMAND))
+        else if (std::strstr (argv[i], GET_CODE_ADDRESS_PREFIX))
         {
+            // Defaut to providing the address of main.
+            void (*func_p)() = nullptr;
+
+            if (std::strstr (argv[i] + strlen (GET_CODE_ADDRESS_PREFIX), "hello"))
+                func_p = hello;
+
 			pthread_mutex_lock (&g_print_mutex);
-            printf ("code address: %p\n", main);
+            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
+            {
+                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.
@@ -276,7 +304,7 @@ int main (int argc, char **argv)
 			{
 				// Create a new thread.
 				pthread_t new_thread;
-				const int err = ::pthread_create (&new_thread, NULL, thread_func, NULL);
+				const int err = ::pthread_create (&new_thread, nullptr, thread_func, nullptr);
 			    if (err)
 				{
 					fprintf (stderr, "pthread_create() failed with error code %d\n", err);
@@ -316,7 +344,7 @@ int main (int argc, char **argv)
 	// If we launched any threads, join them
 	for (std::vector<pthread_t>::iterator it = threads.begin (); it != threads.end (); ++it)
 	{
-		void *thread_retval = NULL;
+		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);





More information about the lldb-commits mailing list