Fixed up gdb-remote auxv regex issues with binary data.
authorTodd Fiala <todd.fiala@gmail.com>
Thu, 19 Jun 2014 17:35:40 +0000 (17:35 +0000)
committerTodd Fiala <todd.fiala@gmail.com>
Thu, 19 Jun 2014 17:35:40 +0000 (17:35 +0000)
Fixes two causes for https://github.com/tfiala/lldb/issues/7.

1. Ensures the inferior program has started executing, by printing
a message on output first thing (per the "message:" command line arg)
and waiting for that text to arrive before doing any checks related
to auxv support.

2. Fixes up auxv-related regex patterns to be compiled with the Python
re.MULTILINE and re.DOTALL options.  The multiline is needed because
the binary data can include what look like newlines when interpreted
as text, and the DOTALL is needed to have the (.*) content portion match
newlines.

Added interrupt packet helper methods to add interrupt test sequence
packets and parse the results from them.

llvm-svn: 211283

lldb/test/tools/lldb-gdbserver/TestGdbRemoteAuxvSupport.py
lldb/test/tools/lldb-gdbserver/gdbremote_testcase.py
lldb/test/tools/lldb-gdbserver/lldbgdbserverutils.py

index b11d7cf..67b575b 100644 (file)
@@ -7,8 +7,22 @@ class TestGdbRemoteAuxvSupport(gdbremote_testcase.GdbRemoteTestCaseBase):
 
     AUXV_SUPPORT_FEATURE_NAME = "qXfer:auxv:read"
 
-    def has_auxv_support(self, inferior_args=None):
+    def has_auxv_support(self):
+        inferior_args = ["message:main entered", "sleep:5"]
         procs = self.prep_debug_monitor_and_inferior(inferior_args=inferior_args)
+
+        # Don't do anything until we match the launched inferior main entry output.
+        # Then immediately interrupt the process.
+        # This prevents auxv data being asked for before it's ready and leaves
+        # us in a stopped state.
+        self.test_sequence.add_log_lines([
+            # Start the inferior...
+            "read packet: $c#00",
+            # ... match output....
+            { "type":"output_match", "regex":r"^message:main entered\r\n$" },
+            ], True)
+        # ... then interrupt.
+        self.add_interrupt_packets()
         self.add_qSupported_packets()
 
         context = self.expect_gdbremote_sequence()
@@ -17,9 +31,9 @@ class TestGdbRemoteAuxvSupport(gdbremote_testcase.GdbRemoteTestCaseBase):
         features = self.parse_qSupported_response(context)
         return self.AUXV_SUPPORT_FEATURE_NAME in features and features[self.AUXV_SUPPORT_FEATURE_NAME] == "+"
 
-    def get_raw_auxv_data(self, inferior_args=None):
+    def get_raw_auxv_data(self):
         # Start up llgs and inferior, and check for auxv support.
-        if not self.has_auxv_support(inferior_args=inferior_args):
+        if not self.has_auxv_support():
             self.skipTest("auxv data not supported")
 
         # Grab pointer size for target.  We'll assume that is equivalent to an unsigned long on the target.
@@ -42,7 +56,7 @@ class TestGdbRemoteAuxvSupport(gdbremote_testcase.GdbRemoteTestCaseBase):
         self.reset_test_sequence()
         self.test_sequence.add_log_lines([
             "read packet: $qXfer:auxv:read::{:x},{:x}:#00".format(OFFSET, LENGTH),
-            {"direction":"send", "regex":r"^\$([^E])(.*)#[0-9a-fA-F]{2}$", "capture":{1:"response_type", 2:"content_raw"} }
+            {"direction":"send", "regex":re.compile(r"^\$([^E])(.*)#[0-9a-fA-F]{2}$", re.MULTILINE|re.DOTALL), "capture":{1:"response_type", 2:"content_raw"} }
             ], True)
 
         context = self.expect_gdbremote_sequence()
@@ -57,10 +71,10 @@ class TestGdbRemoteAuxvSupport(gdbremote_testcase.GdbRemoteTestCaseBase):
         self.assertIsNotNone(content_raw)
         return (word_size, self.decode_gdbremote_binary(content_raw))
 
-    def supports_auxv(self, inferior_args=None):
+    def supports_auxv(self):
         # When non-auxv platforms support llgs, skip the test on platforms
         # that don't support auxv.
-        self.assertTrue(self.has_auxv_support(inferior_args=inferior_args))
+        self.assertTrue(self.has_auxv_support())
 
     #
     # We skip the "supports_auxv" test on debugserver.  The rest of the tests
@@ -80,7 +94,7 @@ class TestGdbRemoteAuxvSupport(gdbremote_testcase.GdbRemoteTestCaseBase):
         self.supports_auxv()
 
     def auxv_data_is_correct_size(self):
-        (word_size, auxv_data) = self.get_raw_auxv_data(inferior_args=["sleep:1"])
+        (word_size, auxv_data) = self.get_raw_auxv_data()
         self.assertIsNotNone(auxv_data)
 
         # Ensure auxv data is a multiple of 2*word_size (there should be two unsigned long fields per auxv entry).
@@ -105,7 +119,7 @@ class TestGdbRemoteAuxvSupport(gdbremote_testcase.GdbRemoteTestCaseBase):
         self.auxv_data_is_correct_size()
 
     def auxv_keys_look_valid(self):
-        (word_size, auxv_data) = self.get_raw_auxv_data(inferior_args=["sleep:1"])
+        (word_size, auxv_data) = self.get_raw_auxv_data()
         self.assertIsNotNone(auxv_data)
 
         # Grab endian.
@@ -150,7 +164,7 @@ class TestGdbRemoteAuxvSupport(gdbremote_testcase.GdbRemoteTestCaseBase):
         # return the same data as a single larger read.
 
         # Grab the auxv data with a single large read here.
-        (word_size, auxv_data) = self.get_raw_auxv_data(inferior_args=["sleep:1"])
+        (word_size, auxv_data) = self.get_raw_auxv_data()
         self.assertIsNotNone(auxv_data)
 
         # Grab endian.
index 0d122b3..653ba0c 100644 (file)
@@ -642,7 +642,7 @@ class GdbRemoteTestCaseBase(TestBase):
             self.reset_test_sequence()
             self.test_sequence.add_log_lines([
                 "read packet: ${}{:x},{:x}:#00".format(command_prefix, offset, chunk_length),
-                {"direction":"send", "regex":r"^\$([^E])(.*)#[0-9a-fA-F]{2}$", "capture":{1:"response_type", 2:"content_raw"} }
+                {"direction":"send", "regex":re.compile(r"^\$([^E])(.*)#[0-9a-fA-F]{2}$", re.MULTILINE|re.DOTALL), "capture":{1:"response_type", 2:"content_raw"} }
                 ], True)
 
             context = self.expect_gdbremote_sequence()
@@ -664,3 +664,16 @@ class GdbRemoteTestCaseBase(TestBase):
                 self.assertIsNotNone(content_raw)
                 decoded_data += self.decode_gdbremote_binary(content_raw)
         return decoded_data
+
+    def add_interrupt_packets(self):
+        self.test_sequence.add_log_lines([
+            # Send the intterupt.
+            "read packet: {}".format(chr(03)),
+            # And wait for the stop notification.
+            {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})(.*)#[0-9a-fA-F]{2}$", "capture":{1:"stop_signo", 2:"stop_key_val_text" } },
+            ], True)
+
+    def parse_interrupt_packets(self, context):
+        self.assertIsNotNone(context.get("stop_signo"))
+        self.assertIsNotNone(context.get("stop_key_val_text"))
+        return (int(context["stop_signo"], 16), self.parse_key_val_dict(context["stop_key_val_text"]))
\ No newline at end of file
index cdd19d4..01ff2ce 100644 (file)
@@ -463,7 +463,8 @@ class GdbRemoteEntry(GdbRemoteEntryBase):
     def _assert_regex_match(self, asserter, actual_packet, context):
         # Ensure the actual packet matches from the start of the actual packet.
         match = self.regex.match(actual_packet)
-        asserter.assertIsNotNone(match)
+        if not match:
+            asserter.fail("regex '{}' failed to match against content '{}'".format(self.regex.pattern, actual_packet))
 
         if self.capture:
             # Handle captures.