199451b44SJordan Rupprechtimport unittest2 299451b44SJordan Rupprechtimport gdbremote_testcase 399451b44SJordan Rupprechtfrom lldbsuite.test.decorators import * 499451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import * 599451b44SJordan Rupprechtfrom lldbsuite.test import lldbutil 699451b44SJordan Rupprecht 799451b44SJordan Rupprechtclass TestGdbRemote_qThreadStopInfo(gdbremote_testcase.GdbRemoteTestCaseBase): 899451b44SJordan Rupprecht THREAD_COUNT = 5 999451b44SJordan Rupprecht 10*29caa858SPavel Labath def gather_stop_replies_via_qThreadStopInfo(self, threads): 1199451b44SJordan Rupprecht # Grab stop reply for each thread via qThreadStopInfo{tid:hex}. 1299451b44SJordan Rupprecht stop_replies = {} 1399451b44SJordan Rupprecht thread_dicts = {} 1499451b44SJordan Rupprecht for thread in threads: 1599451b44SJordan Rupprecht # Run the qThreadStopInfo command. 1699451b44SJordan Rupprecht self.reset_test_sequence() 1799451b44SJordan Rupprecht self.test_sequence.add_log_lines( 1899451b44SJordan Rupprecht [ 1999451b44SJordan Rupprecht "read packet: $qThreadStopInfo{:x}#00".format(thread), 2099451b44SJordan Rupprecht { 2199451b44SJordan Rupprecht "direction": "send", 2299451b44SJordan Rupprecht "regex": r"^\$T([0-9a-fA-F]+)([^#]+)#[0-9a-fA-F]{2}$", 2399451b44SJordan Rupprecht "capture": { 2499451b44SJordan Rupprecht 1: "stop_result", 2599451b44SJordan Rupprecht 2: "key_vals_text"}}, 2699451b44SJordan Rupprecht ], 2799451b44SJordan Rupprecht True) 2899451b44SJordan Rupprecht context = self.expect_gdbremote_sequence() 2999451b44SJordan Rupprecht self.assertIsNotNone(context) 3099451b44SJordan Rupprecht 3199451b44SJordan Rupprecht # Parse stop reply contents. 3299451b44SJordan Rupprecht key_vals_text = context.get("key_vals_text") 3399451b44SJordan Rupprecht self.assertIsNotNone(key_vals_text) 3499451b44SJordan Rupprecht kv_dict = self.parse_key_val_dict(key_vals_text) 3599451b44SJordan Rupprecht self.assertIsNotNone(kv_dict) 3699451b44SJordan Rupprecht 3799451b44SJordan Rupprecht # Verify there is a thread and that it matches the expected thread 3899451b44SJordan Rupprecht # id. 3999451b44SJordan Rupprecht kv_thread = kv_dict.get("thread") 4099451b44SJordan Rupprecht self.assertIsNotNone(kv_thread) 4199451b44SJordan Rupprecht kv_thread_id = int(kv_thread, 16) 4299451b44SJordan Rupprecht self.assertEqual(kv_thread_id, thread) 4399451b44SJordan Rupprecht 4499451b44SJordan Rupprecht # Grab the stop id reported. 4599451b44SJordan Rupprecht stop_result_text = context.get("stop_result") 4699451b44SJordan Rupprecht self.assertIsNotNone(stop_result_text) 4799451b44SJordan Rupprecht stop_replies[kv_thread_id] = int(stop_result_text, 16) 4899451b44SJordan Rupprecht 4999451b44SJordan Rupprecht # Hang on to the key-val dictionary for the thread. 5099451b44SJordan Rupprecht thread_dicts[kv_thread_id] = kv_dict 5199451b44SJordan Rupprecht 52*29caa858SPavel Labath return stop_replies 5399451b44SJordan Rupprecht 5476a718eeSPavel Labath @skipIfNetBSD 5576a718eeSPavel Labath def test_qThreadStopInfo_works_for_multiple_threads(self): 5676a718eeSPavel Labath self.build() 5776a718eeSPavel Labath self.set_inferior_startup_launch() 58*29caa858SPavel Labath _, threads = self.launch_with_threads(self.THREAD_COUNT) 59*29caa858SPavel Labath stop_replies = self.gather_stop_replies_via_qThreadStopInfo(threads) 6099451b44SJordan Rupprecht triple = self.dbg.GetSelectedPlatform().GetTriple() 6199451b44SJordan Rupprecht # Consider one more thread created by calling DebugBreakProcess. 6299451b44SJordan Rupprecht if re.match(".*-.*-windows", triple): 6376a718eeSPavel Labath self.assertGreaterEqual(len(stop_replies), self.THREAD_COUNT) 6499451b44SJordan Rupprecht else: 6576a718eeSPavel Labath self.assertEqual(len(stop_replies), self.THREAD_COUNT) 6699451b44SJordan Rupprecht 6776a718eeSPavel Labath @expectedFailureAll(oslist=["freebsd"], bugnumber="llvm.org/pr48418") 6876a718eeSPavel Labath @expectedFailureNetBSD 69*29caa858SPavel Labath @expectedFailureAll(oslist=["windows"]) # Output forwarding not implemented 7076a718eeSPavel Labath def test_qThreadStopInfo_only_reports_one_thread_stop_reason_during_interrupt(self): 7199451b44SJordan Rupprecht self.build() 7299451b44SJordan Rupprecht self.set_inferior_startup_launch() 73*29caa858SPavel Labath procs = self.prep_debug_monitor_and_inferior( 74*29caa858SPavel Labath inferior_args=["thread:new"]*4 + ["stop-me-now", "sleep:60"]) 7599451b44SJordan Rupprecht 76*29caa858SPavel Labath self.test_sequence.add_log_lines([ 77*29caa858SPavel Labath "read packet: $c#00", 78*29caa858SPavel Labath {"type": "output_match", 79*29caa858SPavel Labath "regex": self.maybe_strict_output_regex(r"stop-me-now\r\n")}, 80*29caa858SPavel Labath "read packet: \x03", 81*29caa858SPavel Labath {"direction": "send", 82*29caa858SPavel Labath "regex": r"^\$T([0-9a-fA-F]{2})([^#]*)#..$"}], True) 83*29caa858SPavel Labath self.add_threadinfo_collection_packets() 84*29caa858SPavel Labath context = self.expect_gdbremote_sequence() 85*29caa858SPavel Labath threads = self.parse_threadinfo_packets(context) 86*29caa858SPavel Labath 87*29caa858SPavel Labath stop_replies = self.gather_stop_replies_via_qThreadStopInfo(threads) 8899451b44SJordan Rupprecht self.assertIsNotNone(stop_replies) 8999451b44SJordan Rupprecht 9099451b44SJordan Rupprecht no_stop_reason_count = sum( 9199451b44SJordan Rupprecht 1 for stop_reason in list( 9299451b44SJordan Rupprecht stop_replies.values()) if stop_reason == 0) 9399451b44SJordan Rupprecht with_stop_reason_count = sum( 9499451b44SJordan Rupprecht 1 for stop_reason in list( 9599451b44SJordan Rupprecht stop_replies.values()) if stop_reason != 0) 9699451b44SJordan Rupprecht 9799451b44SJordan Rupprecht # All but one thread should report no stop reason. 9899451b44SJordan Rupprecht triple = self.dbg.GetSelectedPlatform().GetTriple() 9999451b44SJordan Rupprecht 10099451b44SJordan Rupprecht # Consider one more thread created by calling DebugBreakProcess. 10199451b44SJordan Rupprecht if re.match(".*-.*-windows", triple): 10276a718eeSPavel Labath self.assertGreaterEqual(no_stop_reason_count, self.THREAD_COUNT - 1) 10399451b44SJordan Rupprecht else: 10476a718eeSPavel Labath self.assertEqual(no_stop_reason_count, self.THREAD_COUNT - 1) 10599451b44SJordan Rupprecht 10699451b44SJordan Rupprecht # Only one thread should should indicate a stop reason. 10799451b44SJordan Rupprecht self.assertEqual(with_stop_reason_count, 1) 108