199451b44SJordan Rupprechtimport gdbremote_testcase 299451b44SJordan Rupprechtfrom lldbsuite.test.decorators import * 399451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import * 499451b44SJordan Rupprechtfrom lldbsuite.test import lldbutil 599451b44SJordan Rupprecht 6*2238dcc3SJonas Devlieghere 799451b44SJordan Rupprechtclass TestGdbRemote_qThreadStopInfo(gdbremote_testcase.GdbRemoteTestCaseBase): 899451b44SJordan Rupprecht THREAD_COUNT = 5 999451b44SJordan Rupprecht 1029caa858SPavel 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}$", 23*2238dcc3SJonas Devlieghere "capture": {1: "stop_result", 2: "key_vals_text"}, 24*2238dcc3SJonas Devlieghere }, 2599451b44SJordan Rupprecht ], 26*2238dcc3SJonas Devlieghere True, 27*2238dcc3SJonas Devlieghere ) 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 5229caa858SPavel 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() 5829caa858SPavel Labath _, threads = self.launch_with_threads(self.THREAD_COUNT) 5929caa858SPavel 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 6929caa858SPavel 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() 7329caa858SPavel Labath procs = self.prep_debug_monitor_and_inferior( 74*2238dcc3SJonas Devlieghere inferior_args=["thread:new"] * 4 + ["stop-me-now", "sleep:60"] 75*2238dcc3SJonas Devlieghere ) 7699451b44SJordan Rupprecht 77*2238dcc3SJonas Devlieghere self.test_sequence.add_log_lines( 78*2238dcc3SJonas Devlieghere [ 7929caa858SPavel Labath "read packet: $c#00", 80*2238dcc3SJonas Devlieghere { 81*2238dcc3SJonas Devlieghere "type": "output_match", 82*2238dcc3SJonas Devlieghere "regex": self.maybe_strict_output_regex(r"stop-me-now\r\n"), 83*2238dcc3SJonas Devlieghere }, 8429caa858SPavel Labath "read packet: \x03", 85*2238dcc3SJonas Devlieghere {"direction": "send", "regex": r"^\$T([0-9a-fA-F]{2})([^#]*)#..$"}, 86*2238dcc3SJonas Devlieghere ], 87*2238dcc3SJonas Devlieghere True, 88*2238dcc3SJonas Devlieghere ) 8929caa858SPavel Labath self.add_threadinfo_collection_packets() 9029caa858SPavel Labath context = self.expect_gdbremote_sequence() 9129caa858SPavel Labath threads = self.parse_threadinfo_packets(context) 9229caa858SPavel Labath 9329caa858SPavel Labath stop_replies = self.gather_stop_replies_via_qThreadStopInfo(threads) 9499451b44SJordan Rupprecht self.assertIsNotNone(stop_replies) 9599451b44SJordan Rupprecht 9699451b44SJordan Rupprecht no_stop_reason_count = sum( 97*2238dcc3SJonas Devlieghere 1 for stop_reason in list(stop_replies.values()) if stop_reason == 0 98*2238dcc3SJonas Devlieghere ) 9999451b44SJordan Rupprecht with_stop_reason_count = sum( 100*2238dcc3SJonas Devlieghere 1 for stop_reason in list(stop_replies.values()) if stop_reason != 0 101*2238dcc3SJonas Devlieghere ) 10299451b44SJordan Rupprecht 10399451b44SJordan Rupprecht # All but one thread should report no stop reason. 10499451b44SJordan Rupprecht triple = self.dbg.GetSelectedPlatform().GetTriple() 10599451b44SJordan Rupprecht 10699451b44SJordan Rupprecht # Consider one more thread created by calling DebugBreakProcess. 10799451b44SJordan Rupprecht if re.match(".*-.*-windows", triple): 10876a718eeSPavel Labath self.assertGreaterEqual(no_stop_reason_count, self.THREAD_COUNT - 1) 10999451b44SJordan Rupprecht else: 11076a718eeSPavel Labath self.assertEqual(no_stop_reason_count, self.THREAD_COUNT - 1) 11199451b44SJordan Rupprecht 11299451b44SJordan Rupprecht # Only one thread should should indicate a stop reason. 11399451b44SJordan Rupprecht self.assertEqual(with_stop_reason_count, 1) 114