[Lldb-commits] [lldb] r210196 - Added gdb-remote $qMemoryRegionInfo tests for heap and stack.

Todd Fiala todd.fiala at gmail.com
Wed Jun 4 09:42:12 PDT 2014


Author: tfiala
Date: Wed Jun  4 11:42:12 2014
New Revision: 210196

URL: http://llvm.org/viewvc/llvm-project?rev=210196&view=rev
Log:
Added gdb-remote $qMemoryRegionInfo tests for heap and stack.

Added two new tests: one to verify that a test exe heap address
returned is readable and writeable, and a similar one to verify
a test exe stack address is readable and writeable.

Ran the main.cpp test exe code through the Xcode re-indenter.
I was using TextMate to edit the test's C++ code alongside the
Python code but last check-in found that it was not handling
tabs/indentation the way I am intending it.

Modified test exe to require C++11.

Refactored gdb remote python code's handling of memory region
info into more re-usable methods.

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

Modified: lldb/trunk/test/tools/lldb-gdbserver/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/Makefile?rev=210196&r1=210195&r2=210196&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/Makefile (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/Makefile Wed Jun  4 11:42:12 2014
@@ -1,6 +1,6 @@
 LEVEL = ../../make
 
-CFLAGS_EXTRAS := -D__STDC_LIMIT_MACROS -D__STDC_FORMAT_MACROS
+CFLAGS_EXTRAS := -D__STDC_LIMIT_MACROS -D__STDC_FORMAT_MACROS -std=c++11
 LD_EXTRAS := -lpthread
 CXX_SOURCES := main.cpp
 MAKE_DSYM :=NO

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=210196&r1=210195&r2=210196&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py Wed Jun  4 11:42:12 2014
@@ -255,7 +255,34 @@ class LldbGdbServerTestCase(TestBase):
         self.assertTrue("encoding" in reg_info)
         self.assertTrue("format" in reg_info)
 
-    def assert_address_within_range(self, test_address, range_start, range_size):
+    def add_query_memory_region_packets(self, address):
+        self.test_sequence.add_log_lines(
+            ["read packet: $qMemoryRegionInfo:{0:x}#00".format(address),
+             {"direction":"send", "regex":r"^\$(.+)#[0-9a-fA-F]{2}$", "capture":{1:"memory_region_response"} }],
+            True)
+        
+    def parse_memory_region_packet(self, context):
+        # Ensure we have a context.
+        self.assertIsNotNone(context.get("memory_region_response"))
+        
+        # Pull out key:value; pairs.
+        mem_region_dict = {match.group(1):match.group(2) for match in re.finditer(r"([^:]+):([^;]+);", context.get("memory_region_response"))}
+
+        # Validate keys are known.
+        for (key, val) in mem_region_dict.items():
+            self.assertTrue(key in ["start", "size", "permissions", "error"])
+            self.assertIsNotNone(val)
+
+        # Return the dictionary of key-value pairs for the memory region.
+        return mem_region_dict
+
+    def assert_address_within_memory_region(self, test_address, mem_region_dict):
+        self.assertIsNotNone(mem_region_dict)
+        self.assertTrue("start" in mem_region_dict)
+        self.assertTrue("size" in mem_region_dict)
+        
+        range_start = int(mem_region_dict["start"], 16)
+        range_size = int(mem_region_dict["size"], 16)
         range_end = range_start + range_size
 
         if test_address < range_start:
@@ -1350,35 +1377,20 @@ class LldbGdbServerTestCase(TestBase):
 
         # Grab memory region info from the inferior.
         self.reset_test_sequence()
-        self.test_sequence.add_log_lines(
-            ["read packet: $qMemoryRegionInfo:{0:x}#00".format(code_address),
-             {"direction":"send", "regex":r"^\$(.+)#[0-9a-fA-F]{2}$", "capture":{1:"memory_region_response"} }],
-            True)
+        self.add_query_memory_region_packets(code_address)
 
         # Run the packet stream.
         context = self.expect_gdbremote_sequence()
         self.assertIsNotNone(context)
-
-        # Parse the memory region response
-        self.assertIsNotNone(context.get("memory_region_response"))
-        mem_region_dict = {match.group(1):match.group(2) for match in re.finditer(r"([^:]+):([^;]+);", context.get("memory_region_response"))}
-        # print "mem_region_dict: {}".format(mem_region_dict)
-        
-        for (key, val) in mem_region_dict.items():
-            self.assertTrue(key in ["start", "size", "permissions", "error"])
-            self.assertIsNotNone(val)
+        mem_region_dict = self.parse_memory_region_packet(context)
 
         # Ensure code address is readable and executable.
         self.assertTrue("permissions" in mem_region_dict)
         self.assertTrue("r" in mem_region_dict["permissions"])
         self.assertTrue("x" in mem_region_dict["permissions"])
-
-        # Ensure it has a start address and a size.
-        self.assertTrue("start" in mem_region_dict)
-        self.assertTrue("size" in mem_region_dict)
         
         # Ensure the start address and size encompass the address we queried.
-        self.assert_address_within_range(code_address, int(mem_region_dict["start"], 16), int(mem_region_dict["size"], 16))
+        self.assert_address_within_memory_region(code_address, mem_region_dict)
         
 
     @debugserver_test
@@ -1398,6 +1410,129 @@ class LldbGdbServerTestCase(TestBase):
         self.set_inferior_startup_launch()
         self.qMemoryRegionInfo_reports_code_address_as_executable()
 
+    def qMemoryRegionInfo_reports_stack_address_as_readable_writeable(self):
+        # Start up the inferior.
+        procs = self.prep_debug_monitor_and_inferior(
+            inferior_args=["get-stack-address-hex:", "sleep:5"])
+
+        # 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 message buffer within the inferior. 
+             # Note we require launch-only testing so we can get inferior otuput.
+             { "type":"output_match", "regex":r"^stack address: 0x([0-9a-fA-F]+)\r\n$", "capture":{ 1:"stack_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("stack_address"))
+        stack_address = int(context.get("stack_address"), 16)
+
+        # Grab memory region info from the inferior.
+        self.reset_test_sequence()
+        self.add_query_memory_region_packets(stack_address)
+
+        # Run the packet stream.
+        context = self.expect_gdbremote_sequence()
+        self.assertIsNotNone(context)
+        mem_region_dict = self.parse_memory_region_packet(context)
+
+        # Ensure address is readable and executable.
+        self.assertTrue("permissions" in mem_region_dict)
+        self.assertTrue("r" in mem_region_dict["permissions"])
+        self.assertTrue("w" in mem_region_dict["permissions"])
+
+        # Ensure the start address and size encompass the address we queried.
+        self.assert_address_within_memory_region(stack_address, mem_region_dict)
+
+
+    @debugserver_test
+    @dsym_test
+    def test_qMemoryRegionInfo_reports_stack_address_as_readable_writeable_debugserver_dsym(self):
+        self.init_debugserver_test()
+        self.buildDsym()
+        self.set_inferior_startup_launch()
+        self.qMemoryRegionInfo_reports_stack_address_as_readable_writeable()
+
+    @llgs_test
+    @dwarf_test
+    @unittest2.expectedFailure()
+    def test_qMemoryRegionInfo_reports_stack_address_as_readable_writeable_llgs_dwarf(self):
+        self.init_llgs_test()
+        self.buildDwarf()
+        self.set_inferior_startup_launch()
+        self.qMemoryRegionInfo_reports_stack_address_as_readable_writeable()
+
+    def qMemoryRegionInfo_reports_heap_address_as_readable_writeable(self):
+        # Start up the inferior.
+        procs = self.prep_debug_monitor_and_inferior(
+            inferior_args=["get-heap-address-hex:", "sleep:5"])
+
+        # 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 message buffer within the inferior. 
+             # Note we require launch-only testing so we can get inferior otuput.
+             { "type":"output_match", "regex":r"^heap address: 0x([0-9a-fA-F]+)\r\n$", "capture":{ 1:"heap_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("heap_address"))
+        heap_address = int(context.get("heap_address"), 16)
+
+        # Grab memory region info from the inferior.
+        self.reset_test_sequence()
+        self.add_query_memory_region_packets(heap_address)
+
+        # Run the packet stream.
+        context = self.expect_gdbremote_sequence()
+        self.assertIsNotNone(context)
+        mem_region_dict = self.parse_memory_region_packet(context)
+
+        # Ensure address is readable and executable.
+        self.assertTrue("permissions" in mem_region_dict)
+        self.assertTrue("r" in mem_region_dict["permissions"])
+        self.assertTrue("w" in mem_region_dict["permissions"])
+
+        # Ensure the start address and size encompass the address we queried.
+        self.assert_address_within_memory_region(heap_address, mem_region_dict)
+
+
+    @debugserver_test
+    @dsym_test
+    def test_qMemoryRegionInfo_reports_heap_address_as_readable_writeable_debugserver_dsym(self):
+        self.init_debugserver_test()
+        self.buildDsym()
+        self.set_inferior_startup_launch()
+        self.qMemoryRegionInfo_reports_heap_address_as_readable_writeable()
+
+    @llgs_test
+    @dwarf_test
+    @unittest2.expectedFailure()
+    def test_qMemoryRegionInfo_reports_heap_address_as_readable_writeable_llgs_dwarf(self):
+        self.init_llgs_test()
+        self.buildDwarf()
+        self.set_inferior_startup_launch()
+        self.qMemoryRegionInfo_reports_heap_address_as_readable_writeable()
 
 
 if __name__ == '__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=210196&r1=210195&r2=210196&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/main.cpp (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/main.cpp Wed Jun  4 11:42:12 2014
@@ -2,6 +2,7 @@
 #include <cstring>
 #include <errno.h>
 #include <inttypes.h>
+#include <memory>
 #include <pthread.h>
 #include <setjmp.h>
 #include <signal.h>
@@ -29,9 +30,9 @@ static const char *const GET_HEAP_ADDRES
 static const char *const GET_CODE_ADDRESS_COMMAND = "get-code-address-hex:";
 
 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 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;
@@ -84,21 +85,21 @@ signal_handler (int signo)
 	// Reset the signal handler if we're one of the expected signal handlers.
 	switch (signo)
 	{
-	case SIGSEGV:
-		// 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;
+        case SIGSEGV:
+            // 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.
@@ -139,7 +140,7 @@ thread_func (void *arg)
 		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;
@@ -166,7 +167,7 @@ thread_func (void *arg)
 		printf (": past SIGSEGV\n");
 		pthread_mutex_unlock (&g_print_mutex);
 	}
-	
+
 	int sleep_seconds_remaining = 5;
 	while (sleep_seconds_remaining > 0)
 	{
@@ -203,7 +204,7 @@ int main (int argc, char **argv)
 		fprintf(stderr, "failed to set SIGUSR1 handler: errno=%d\n", errno);
 		exit (1);
 	}
-	
+
 	// Process command line args.
     for (int i = 1; i < argc; ++i)
     {
@@ -221,7 +222,7 @@ int main (int argc, char **argv)
         {
             // 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)
@@ -238,7 +239,7 @@ int main (int argc, char **argv)
 
 			// Ensure we're null terminated.
 			g_message[sizeof (g_message) - 1] = '\0';
-			
+
 		}
         else if (std::strstr (argv[i], GET_MESSAGE_ADDRESS_COMMAND))
         {
@@ -251,7 +252,7 @@ int main (int argc, char **argv)
 			// 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);
@@ -287,7 +288,7 @@ int main (int argc, char **argv)
 			{
 				// Turn on thread id announcing.
 				g_print_thread_ids = true;
-				
+
 				// And announce us.
 				pthread_mutex_lock (&g_print_mutex);
 				printf ("thread 0 id: ");
@@ -320,6 +321,6 @@ int main (int argc, char **argv)
 	    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