Add gdb-remote test for $qMemoryRegionInfo code querying.
authorTodd Fiala <todd.fiala@gmail.com>
Wed, 4 Jun 2014 15:44:33 +0000 (15:44 +0000)
committerTodd Fiala <todd.fiala@gmail.com>
Wed, 4 Jun 2014 15:44:33 +0000 (15:44 +0000)
Added test stub for collecting a code, heap and stack address.

Added test to verify that the code address returns a readable,
executable memory region and that the memory region range
was indeed the one that the code belonged to.

llvm-svn: 210187

lldb/test/tools/lldb-gdbserver/TestLldbGdbServer.py
lldb/test/tools/lldb-gdbserver/main.cpp

index 2679443..76f8e4f 100644 (file)
@@ -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"m_packet_reads_memory", self._testMethodName):
+        # if not re.search(r"qMemoryRegionInfo", self._testMethodName):
         #     self.skipTest("focusing on one test")
 
     def reset_test_sequence(self):
@@ -255,6 +255,14 @@ 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):
+        range_end = range_start + range_size
+
+        if test_address < range_start:
+            self.fail("address 0x{0:x} comes before range 0x{1:x} - 0x{2:x} (size 0x{3:x})".format(test_address, range_start, range_end, range_size))
+        elif test_address >= range_end:
+            self.fail("address 0x{0:x} comes after range 0x{1:x} - 0x{2:x} (size 0x{3:x})".format(test_address, range_start, range_end, range_size))
+
     def add_threadinfo_collection_packets(self):
         self.test_sequence.add_log_lines(
             [ { "type":"multi_response", "first_query":"qfThreadInfo", "next_query":"qsThreadInfo",
@@ -1313,6 +1321,84 @@ class LldbGdbServerTestCase(TestBase):
         self.set_inferior_startup_launch()
         self.qMemoryRegionInfo_is_supported()
 
+    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"])
+
+        # 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"^code address: 0x([0-9a-fA-F]+)\r\n$", "capture":{ 1:"code_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 code address.
+        self.assertIsNotNone(context.get("code_address"))
+        code_address = int(context.get("code_address"), 16)
+
+        # 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)
+
+        # 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)
+
+        # 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))
+        
+
+    @debugserver_test
+    @dsym_test
+    def test_qMemoryRegionInfo_reports_code_address_as_executable_debugserver_dsym(self):
+        self.init_debugserver_test()
+        self.buildDsym()
+        self.set_inferior_startup_launch()
+        self.qMemoryRegionInfo_reports_code_address_as_executable()
+
+    @llgs_test
+    @dwarf_test
+    @unittest2.expectedFailure()
+    def test_qMemoryRegionInfo_reports_code_address_as_executable_llgs_dwarf(self):
+        self.init_llgs_test()
+        self.buildDwarf()
+        self.set_inferior_startup_launch()
+        self.qMemoryRegionInfo_reports_code_address_as_executable()
+
+
 
 if __name__ == '__main__':
     unittest2.main()
index 874a69d..4a2784a 100644 (file)
@@ -24,6 +24,9 @@ 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 THREAD_PREFIX = "thread:";
 static const char *const THREAD_COMMAND_NEW = "new"; 
@@ -176,6 +179,7 @@ thread_func (void *arg)
 int main (int argc, char **argv)
 {
        std::vector<pthread_t> threads;
+       std::unique_ptr<uint8_t[]> heap_array_up;
     int return_value = 0;
 
        // Set the signal handler.
@@ -242,6 +246,28 @@ int main (int argc, char **argv)
             printf ("message address: %p\n", &g_message[0]);
                        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_COMMAND))
+        {
+                       pthread_mutex_lock (&g_print_mutex);
+            printf ("code address: %p\n", main);
+                       pthread_mutex_unlock (&g_print_mutex);
+        }
                else if (std::strstr (argv[i], THREAD_PREFIX))
                {
                        // Check if we're creating a new thread.