labath created this revision.
labath added a reviewer: mgorny.
labath requested review of this revision.
Herald added a project: LLDB.

The goal is to replace the awkward add_log_lines dance.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D100964

Files:
  lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
  lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
  lldb/test/API/tools/lldb-server/main.cpp

Index: lldb/test/API/tools/lldb-server/main.cpp
===================================================================
--- lldb/test/API/tools/lldb-server/main.cpp
+++ lldb/test/API/tools/lldb-server/main.cpp
@@ -177,6 +177,7 @@
       std::lock_guard<std::mutex> lock(g_print_mutex);
       printf("thread %" PRIx64 ": past SIGSEGV\n", get_thread_id());
     }
+    return nullptr;
   }
 
   int sleep_seconds_remaining = 60;
Index: lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
===================================================================
--- lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
+++ lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
@@ -25,77 +25,44 @@
     mydir = TestBase.compute_mydir(__file__)
 
     def test_thread_suffix_supported(self):
-        server = self.connect_to_debug_monitor()
-        self.assertIsNotNone(server)
-
+        self.connect_to_debug_monitor()
         self.do_handshake()
-        self.test_sequence.add_log_lines(
-            ["lldb-server <  26> read packet: $QThreadSuffixSupported#e4",
-             "lldb-server <   6> send packet: $OK#9a"],
-            True)
-
-        self.expect_gdbremote_sequence()
-
+        self.assertPacketResponse(b"QThreadSuffixSupported", b"OK")
 
     def test_list_threads_in_stop_reply_supported(self):
-        server = self.connect_to_debug_monitor()
-        self.assertIsNotNone(server)
-
+        self.connect_to_debug_monitor()
         self.do_handshake()
-        self.test_sequence.add_log_lines(
-            ["lldb-server <  27> read packet: $QListThreadsInStopReply#21",
-             "lldb-server <   6> send packet: $OK#9a"],
-            True)
-        self.expect_gdbremote_sequence()
+        self.assertPacketResponse(b"QListThreadsInStopReply", b"OK")
 
     def test_c_packet_works(self):
         self.build()
-        procs = self.prep_debug_monitor_and_inferior()
-        self.test_sequence.add_log_lines(
-            ["read packet: $c#63",
-             "send packet: $W00#00"],
-            True)
-
-        self.expect_gdbremote_sequence()
+        self.prep_debug_monitor_and_inferior()
+        self.assertPacketResponse(b"c", b"W00")
 
     @skipIfWindows # No pty support to test any inferior output
     def test_inferior_print_exit(self):
         self.build()
-        procs = self.prep_debug_monitor_and_inferior(
-                inferior_args=["hello, world"])
-        self.test_sequence.add_log_lines(
-            ["read packet: $vCont;c#a8",
-             {"type": "output_match", "regex": self.maybe_strict_output_regex(r"hello, world\r\n")},
-             "send packet: $W00#00"],
-            True)
+        self.prep_debug_monitor_and_inferior(inferior_args=["hello, world"])
 
-        context = self.expect_gdbremote_sequence()
-        self.assertIsNotNone(context)
+        self.assertPacketResponse(b"vCont;c", b"W00")
+        self.assertRegex(self._server.consume_accumulated_output(),
+                self.maybe_strict_output_regex(br"hello, world\r\n"))
 
     def test_first_launch_stop_reply_thread_matches_first_qC(self):
         self.build()
-        procs = self.prep_debug_monitor_and_inferior()
-        self.test_sequence.add_log_lines(["read packet: $qC#00",
-                                          {"direction": "send",
-                                           "regex": r"^\$QC([0-9a-fA-F]+)#",
-                                           "capture": {1: "thread_id_QC"}},
-                                          "read packet: $?#00",
-                                          {"direction": "send",
-                                              "regex": r"^\$T[0-9a-fA-F]{2}thread:([0-9a-fA-F]+)",
-                                              "capture": {1: "thread_id_?"}}],
-                                         True)
-        context = self.expect_gdbremote_sequence()
-        self.assertEqual(context.get("thread_id_QC"), context.get("thread_id_?"))
+        self.prep_debug_monitor_and_inferior()
+
+        self.assertPacketResponse(b"qC", re.compile(b"QC(?P<QC>[0-9a-fA-F]+)"))
+        self.assertPacketResponse(b"?",
+                re.compile(b"T[0-9a-fA-F]{2}thread:(?P<q>[0-9a-fA-F]+)"))
+        self.assertEqual(self.captures["QC"], self.captures["q"])
 
     def test_attach_commandline_continue_app_exits(self):
         self.build()
         self.set_inferior_startup_attach()
         procs = self.prep_debug_monitor_and_inferior()
-        self.test_sequence.add_log_lines(
-            ["read packet: $vCont;c#a8",
-             "send packet: $W00#00"],
-            True)
-        self.expect_gdbremote_sequence()
+
+        self.assertPacketResponse(b"c", b"W00")
 
         # Wait a moment for completed and now-detached inferior process to
         # clear.
@@ -115,19 +82,12 @@
     def test_qRegisterInfo_returns_one_valid_result(self):
         self.build()
         self.prep_debug_monitor_and_inferior()
-        self.test_sequence.add_log_lines(
-            ["read packet: $qRegisterInfo0#00",
-             {"direction": "send", "regex": r"^\$(.+);#[0-9A-Fa-f]{2}", "capture": {1: "reginfo_0"}}],
-            True)
 
-        # Run the stream
-        context = self.expect_gdbremote_sequence()
-        self.assertIsNotNone(context)
+        self.assertPacketResponse(b"qRegisterInfo0",
+                re.compile(br"(?P<reginfo_0>.+)"))
 
-        reg_info_packet = context.get("reginfo_0")
-        self.assertIsNotNone(reg_info_packet)
         self.assert_valid_reg_info(
-            lldbgdbserverutils.parse_reg_info_response(reg_info_packet))
+            lldbgdbserverutils.parse_reg_info_response(self.captures["reginfo_0"].decode()))
 
     def test_qRegisterInfo_returns_all_valid_results(self):
         self.build()
@@ -260,14 +220,9 @@
         procs = self.prep_debug_monitor_and_inferior()
 
         self.add_threadinfo_collection_packets()
-        self.test_sequence.add_log_lines(
-            ["read packet: $qC#00",
-             {"direction": "send", "regex": r"^\$QC([0-9a-fA-F]+)#", "capture": {1: "thread_id"}}
-             ], True)
-
-        # Run the packet stream.
         context = self.expect_gdbremote_sequence()
-        self.assertIsNotNone(context)
+
+        self.assertPacketResponse(b"qC", re.compile(b"QC(?P<QC>[0-9a-fA-F]+)"))
 
         # Gather threadinfo entries.
         threads = self.parse_threadinfo_packets(context)
@@ -277,7 +232,7 @@
         self.assertEqual(len(threads), 1)
 
         # We should have a valid thread_id from $QC.
-        QC_thread_id_hex = context.get("thread_id")
+        QC_thread_id_hex = self.captures["QC"]
         self.assertIsNotNone(QC_thread_id_hex)
         QC_thread_id = int(QC_thread_id_hex, 16)
 
@@ -322,24 +277,15 @@
             if not "set" in reg_info:
                 continue
 
-            # Clear existing packet expectations.
-            self.reset_test_sequence()
-
-            # Run the register query
-            self.test_sequence.add_log_lines(
-                ["read packet: $p{0:x}#00".format(reg_index),
-                 {"direction": "send", "regex": r"^\$([0-9a-fA-F]+)#", "capture": {1: "p_response"}}],
-                True)
-            context = self.expect_gdbremote_sequence()
-            self.assertIsNotNone(context)
+            self.assertPacketResponse(b"p%x"%reg_index,
+                    re.compile(b"^[0-9a-fA-F]+$"))
 
             # Verify the response length.
-            p_response = context.get("p_response")
-            self.assertIsNotNone(p_response)
+            p_response = self.captures[0]
 
             # Skip erraneous (unsupported) registers.
             # TODO: remove this once we make unsupported registers disappear.
-            if p_response.startswith("E") and len(p_response) == 3:
+            if p_response[0:1] == b"E" and len(p_response) == 3:
                 continue
 
             if "dynamic_size_dwarf_expr_bytes" in reg_info:
@@ -364,27 +310,15 @@
         threads = self.wait_for_thread_count(3)
         self.assertEqual(len(threads), 3)
 
-        pid_str = ""
+        pid_str = b""
         if pass_pid:
-            pid_str = "p{0:x}.".format(procs["inferior"].pid)
+            pid_str = b"p%x."%procs["inferior"].pid
 
         # verify we can $H to each thead, and $qC matches the thread we set.
         for thread in threads:
             # Change to each thread, verify current thread id.
-            self.reset_test_sequence()
-            self.test_sequence.add_log_lines(
-                ["read packet: $Hg{0}{1:x}#00".format(pid_str, thread),  # Set current thread.
-                 "send packet: $OK#00",
-                 "read packet: $qC#00",
-                 {"direction": "send", "regex": r"^\$QC([0-9a-fA-F]+)#", "capture": {1: "thread_id"}}],
-                True)
-
-            context = self.expect_gdbremote_sequence()
-            self.assertIsNotNone(context)
-
-            # Verify the thread id.
-            self.assertIsNotNone(context.get("thread_id"))
-            self.assertEqual(int(context.get("thread_id"), 16), thread)
+            self.assertPacketResponse(b"Hg%s%x"%(pid_str, thread), b"OK")
+            self.assertPacketResponse(b"qC", b"QC%x"%thread)
 
     @expectedFailureAll(oslist=["windows"]) # expect 4 threads
     def test_Hg_switches_to_3_threads_launch(self):
@@ -416,17 +350,12 @@
         self.assertEqual(len(threads), 2)
 
         if pass_pid == -1:
-            pid_str = "p-1."
+            pid_str = b"p-1."
         else:
-            pid_str = "p{0:x}.".format(pass_pid)
+            pid_str = b"p%x."%pass_pid
         thread = threads[1]
 
-        self.test_sequence.add_log_lines(
-            ["read packet: $Hg{0}{1:x}#00".format(pid_str, thread),  # Set current thread.
-             "send packet: $Eff#00"],
-            True)
-
-        self.expect_gdbremote_sequence()
+        self.assertPacketResponse(b"Hg%s%x"%(pid_str, thread), b"Eff")
 
     @expectedFailureAll(oslist=["windows"])
     @add_test_categories(["llgs"])
@@ -463,14 +392,14 @@
                 # Give time between thread creation/segfaulting for the handler to work.
                 # inferior_args.append("sleep:1")
             inferior_args.append("thread:new")
-        inferior_args.append("sleep:10")
 
         # Launch/attach.  (In our case, this should only ever be launched since
         # we need inferior stdout/stderr).
-        procs = self.prep_debug_monitor_and_inferior(
-            inferior_args=inferior_args)
-        self.test_sequence.add_log_lines(["read packet: $c#63"], True)
-        context = self.expect_gdbremote_sequence()
+        self.prep_debug_monitor_and_inferior(inferior_args=inferior_args)
+
+        stop_regex = re.compile(b"T%02xthread:(?P<tid>[0-9a-fA-F]+);"%segfault_signo)
+        # Run until SIGSEGV comes in.
+        self.assertPacketResponse(b"c", stop_regex)
 
         # Let the inferior process have a few moments to start up the thread when launched.
         # context = self.run_process_then_stop(run_seconds=1)
@@ -482,70 +411,39 @@
         signaled_tids = {}
         print_thread_ids = {}
 
+        sigusr_signo = lldbutil.get_signal_number('SIGUSR1')
         # Switch to each thread, deliver a signal, and verify signal delivery
         for i in range(NUM_THREADS - 1):
-            # Run until SIGSEGV comes in.
-            self.reset_test_sequence()
-            self.test_sequence.add_log_lines([{"direction": "send",
-                                               "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
-                                               "capture": {1: "signo",
-                                                            2: "thread_id"}}],
-                                             True)
-
-            context = self.expect_gdbremote_sequence()
-            self.assertIsNotNone(context)
-            signo = context.get("signo")
-            self.assertEqual(int(signo, 16), segfault_signo)
-
             # Ensure we haven't seen this tid yet.
-            thread_id = int(context.get("thread_id"), 16)
+            thread_id = int(self.captures["tid"], 16)
             self.assertNotIn(thread_id, signaled_tids)
             signaled_tids[thread_id] = 1
 
             # Send SIGUSR1 to the thread that signaled the SIGSEGV.
-            self.reset_test_sequence()
-            self.test_sequence.add_log_lines(
-                [
-                    # Set the continue thread.
-                    # Set current thread.
-                    "read packet: $Hc{0:x}#00".format(thread_id),
-                    "send packet: $OK#00",
-
-                    # Continue sending the signal number to the continue thread.
-                    # The commented out packet is a way to do this same operation without using
-                    # a $Hc (but this test is testing $Hc, so we'll stick with the former).
-                    "read packet: $C{0:x}#00".format(lldbutil.get_signal_number('SIGUSR1')),
-                    # "read packet: $vCont;C{0:x}:{1:x};c#00".format(lldbutil.get_signal_number('SIGUSR1'), thread_id),
-
-                    # FIXME: Linux does not report the thread stop on the delivered signal (SIGUSR1 here).  MacOSX debugserver does.
-                    # But MacOSX debugserver isn't guaranteeing the thread the signal handler runs on, so currently its an XFAIL.
-                    # Need to rectify behavior here.  The linux behavior is more intuitive to me since we're essentially swapping out
-                    # an about-to-be-delivered signal (for which we already sent a stop packet) to a different signal.
-                    # {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} },
-                    #  "read packet: $c#63",
-                    {"type": "output_match", "regex": r"^received SIGUSR1 on thread id: ([0-9a-fA-F]+)\r\nthread ([0-9a-fA-F]+): past SIGSEGV\r\n", "capture": {1: "print_thread_id", 2: "post_handle_thread_id"}},
-                ],
-                True)
-
-            # Run the sequence.
-            context = self.expect_gdbremote_sequence()
-            self.assertIsNotNone(context)
-
-            # Ensure the stop signal is the signal we delivered.
-            # stop_signo = context.get("stop_signo")
-            # self.assertIsNotNone(stop_signo)
-            # self.assertEquals(int(stop_signo,16), lldbutil.get_signal_number('SIGUSR1'))
-
-            # Ensure the stop thread is the thread to which we delivered the signal.
-            # stop_thread_id = context.get("stop_thread_id")
-            # self.assertIsNotNone(stop_thread_id)
-            # self.assertEquals(int(stop_thread_id,16), thread_id)
+            # Set the continue thread.
+            self.assertPacketResponse(b"Hc%x"%thread_id, b"OK")
+
+            # Continue sending the signal number to the continue thread.
+            # FIXME: Linux does not report the thread stop on the delivered
+            # signal (SIGUSR1 here).  MacOSX debugserver does.  But MacOSX
+            # debugserver isn't guaranteeing the thread the signal handler runs
+            # on, so currently its an XFAIL.  Need to rectify behavior here.
+            # The linux behavior is more intuitive to me since we're essentially
+            # swapping out an about-to-be-delivered signal (for which we already
+            # sent a stop packet) to a different signal.
+            self.assertPacketResponse(b"C%x"%sigusr_signo,
+                    stop_regex if i < NUM_THREADS-2 else b"W00")
+
+            output = self._server.consume_accumulated_output()
+            match = re.match(rb"^received SIGUSR1 on thread id: (?P<ptid>[0-9a-fA-F]+)\r\nthread (?P=ptid): past SIGSEGV\r\n", output)
+            self.assertIsNotNone(match, "{!r} did not match".format(output))
 
             # Ensure we haven't seen this thread id yet.  The inferior's
             # self-obtained thread ids are not guaranteed to match the stub
             # tids (at least on MacOSX).
-            print_thread_id = context.get("print_thread_id")
-            self.assertIsNotNone(print_thread_id)
+            # The regex ensures the post signal-handle thread id matches the
+            # thread that initially raised the SIGSEGV.
+            print_thread_id = match["ptid"]
             print_thread_id = int(print_thread_id, 16)
             self.assertNotIn(print_thread_id, print_thread_ids)
 
@@ -553,13 +451,6 @@
             # ensure we don't hit it again.
             print_thread_ids[print_thread_id] = 1
 
-            # Ensure post signal-handle thread id matches the thread that
-            # initially raised the SIGSEGV.
-            post_handle_thread_id = context.get("post_handle_thread_id")
-            self.assertIsNotNone(post_handle_thread_id)
-            post_handle_thread_id = int(post_handle_thread_id, 16)
-            self.assertEqual(post_handle_thread_id, print_thread_id)
-
     @expectedFailureDarwin
     @skipIfWindows # no SIGSEGV support
     @expectedFailureAll(oslist=["freebsd"], bugnumber="llvm.org/pr48419")
@@ -633,16 +524,8 @@
 
     def test_qMemoryRegionInfo_is_supported(self):
         self.build()
-        self.set_inferior_startup_launch()
-        # Start up the inferior.
         procs = self.prep_debug_monitor_and_inferior()
-
-        # Ask if it supports $qMemoryRegionInfo.
-        self.test_sequence.add_log_lines(
-            ["read packet: $qMemoryRegionInfo#00",
-             "send packet: $OK#00"
-             ], True)
-        self.expect_gdbremote_sequence()
+        self.assertPacketResponse(b"qMemoryRegionInfo", b"OK")
 
     @skipIfWindows # No pty support to test any inferior output
     def test_qMemoryRegionInfo_reports_code_address_as_executable(self):
@@ -1076,10 +959,9 @@
     @skipIfWindows
     def test_P_and_p_thread_suffix_work(self):
         self.build()
-        self.set_inferior_startup_launch()
 
         # Startup the inferior with three threads.
-        procs = self.prep_debug_monitor_and_inferior(
+        self.prep_debug_monitor_and_inferior(
             inferior_args=["thread:new", "thread:new"])
         self.add_thread_suffix_request_packets()
         self.add_register_info_collection_packets()
@@ -1121,41 +1003,23 @@
             # If we don't have a next value yet, start it with the initial read
             # value + 1
             if not next_value:
-                # Read pre-existing register value.
-                self.reset_test_sequence()
-                self.test_sequence.add_log_lines(
-                    ["read packet: $p{0:x};thread:{1:x}#00".format(reg_index, thread),
-                     {"direction": "send", "regex": r"^\$([0-9a-fA-F]+)#", "capture": {1: "p_response"}},
-                     ], True)
-                context = self.expect_gdbremote_sequence()
-                self.assertIsNotNone(context)
+                self.assertPacketResponse(b"p%x;thread:%x"%(reg_index, thread),
+                        re.compile(b"^[0-9a-fA-F]+$"))
 
                 # Set the next value to use for writing as the increment plus
                 # current value.
-                p_response = context.get("p_response")
-                self.assertIsNotNone(p_response)
                 next_value = lldbgdbserverutils.unpack_register_hex_unsigned(
-                    endian, p_response)
+                    endian, self.captures[0])
 
             # Set new value using P and thread suffix.
-            self.reset_test_sequence()
-            self.test_sequence.add_log_lines(
-                [
-                    "read packet: $P{0:x}={1};thread:{2:x}#00".format(
-                        reg_index,
-                        lldbgdbserverutils.pack_register_hex(
-                            endian,
-                            next_value,
-                            byte_size=reg_byte_size),
-                        thread),
-                    "send packet: $OK#00",
-                ],
-                True)
-            context = self.expect_gdbremote_sequence()
-            self.assertIsNotNone(context)
+            value_str = lldbgdbserverutils.pack_register_hex(
+                    endian,
+                    next_value,
+                    byte_size=reg_byte_size).encode()
+            self.assertPacketResponse(b"P%x=%s;thread:%x"%(reg_index, value_str, thread), b"OK")
 
             # Save the value we set.
-            expected_reg_values.append(next_value)
+            expected_reg_values.append(value_str)
 
             # Increment value for next thread to use (we want them all
             # different so we can verify they wrote to each thread correctly
@@ -1166,21 +1030,6 @@
         # the register we wrote.
         thread_index = 0
         for thread in threads:
-            # Read pre-existing register value.
-            self.reset_test_sequence()
-            self.test_sequence.add_log_lines(
-                ["read packet: $p{0:x};thread:{1:x}#00".format(reg_index, thread),
-                 {"direction": "send", "regex": r"^\$([0-9a-fA-F]+)#", "capture": {1: "p_response"}},
-                 ], True)
-            context = self.expect_gdbremote_sequence()
-            self.assertIsNotNone(context)
-
-            # Get the register value.
-            p_response = context.get("p_response")
-            self.assertIsNotNone(p_response)
-            read_value = lldbgdbserverutils.unpack_register_hex_unsigned(
-                endian, p_response)
-
-            # Make sure we read back what we wrote.
-            self.assertEqual(read_value, expected_reg_values[thread_index])
+            self.assertPacketResponse(b"p%x;thread:%x"%(reg_index, thread),
+                    expected_reg_values[thread_index])
             thread_index += 1
Index: lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
+++ lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
@@ -120,6 +120,7 @@
     def setUp(self):
         super(GdbRemoteTestCaseBase, self).setUp()
 
+        self.captures = {}
         self.setUpBaseLogging()
         self.debug_monitor_extra_args = []
 
@@ -529,6 +530,7 @@
                 self.add_set_environment_packets(name, value)
         if self._inferior_startup == self._STARTUP_LAUNCH:
             self.add_verified_launch_packets(launch_args)
+        self.expect_gdbremote_sequence()
 
         return {"inferior": inferior, "server": server}
 
@@ -540,6 +542,18 @@
         self.assertEqual(server.get_normal_packet(), b"OK")
         server.send_ack()
 
+    def assertPacketResponse(self, packet, response_pattern):
+        self._server.send_packet(packet)
+        response = self._server.get_normal_packet()
+        if isinstance(response_pattern, re.Pattern):
+            match = response_pattern.match(response)
+            self.assertIsNotNone(match, "{!r} matches {!r}".format(response,
+                response_pattern))
+            self.captures.update(match.groupdict())
+        else:
+            self.assertEqual(response, response_pattern)
+        self.captures[0] = response
+
     def add_verified_launch_packets(self, launch_args):
         self.test_sequence.add_log_lines(
             ["read packet: %s" % build_gdbremote_A_packet(launch_args),
@@ -1570,8 +1584,17 @@
         self.assertEqual(step_count, expected_step_count)
 
     def maybe_strict_output_regex(self, regex):
-        return '.*' + regex + \
-            '.*' if lldbplatformutil.hasChattyStderr(self) else '^' + regex + '$'
+        if lldbplatformutil.hasChattyStderr(self):
+            prefix = b"^"
+            suffix = b"$"
+        else:
+            prefix = suffix = b".*"
+
+        if isinstance(regex, str):
+            prefix = prefix.decode()
+            suffix = suffix.decode()
+
+        return prefix + regex + suffix
 
     def install_and_create_launch_args(self):
         exe_path = self.getBuildArtifact("a.out")
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
  • [Lldb-commits] [PATCH] D1009... Pavel Labath via Phabricator via lldb-commits

Reply via email to