"""Test that we get thread names when interrupting a process.""" import time import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil class TestInterruptThreadNames(TestBase): @skipUnlessDarwin @add_test_categories(["pyapi"]) def test_with_python_api(self): """Test that we get thread names when interrupting a process.""" self.build() exe = self.getBuildArtifact("a.out") target = self.dbg.CreateTarget(exe) self.assertTrue(target, VALID_TARGET) launch_info = target.GetLaunchInfo() error = lldb.SBError() self.dbg.SetAsync(True) process = target.Launch(launch_info, error) self.assertTrue(process, PROCESS_IS_VALID) listener = self.dbg.GetListener() broadcaster = process.GetBroadcaster() rc = broadcaster.AddListener(listener, lldb.SBProcess.eBroadcastBitStateChanged) self.assertNotEqual(rc, 0, "Unable to add listener to process") self.assertTrue( self.wait_for_running(process, listener), "Check that process is up and running", ) inferior_set_up = self.wait_until_program_setup_complete(process, listener) # Check that the program was able to create its threads within the allotted time self.assertTrue(inferior_set_up.IsValid()) self.assertEquals(inferior_set_up.GetValueAsSigned(), 1) self.check_number_of_threads(process) main_thread = lldb.SBThread() second_thread = lldb.SBThread() third_thread = lldb.SBThread() for idx in range(0, process.GetNumThreads()): t = process.GetThreadAtIndex(idx) if t.GetName() == "main thread": main_thread = t if t.GetName() == "second thread": second_thread = t if t.GetName() == "third thread": third_thread = t self.check_expected_threads_present(main_thread, second_thread, third_thread) process.Kill() # The process will set a global variable 'threads_up_and_running' to 1 when # it has has completed its setup. Sleep for one second, pause the program, # check to see if the global has that value, and continue if it does not. def wait_until_program_setup_complete(self, process, listener): inferior_set_up = lldb.SBValue() retry = 5 while retry > 0: arch = self.getArchitecture() # when running the testsuite against a remote arm device, it may take # a little longer for the process to start up. Use a "can't possibly take # longer than this" value. if arch == "arm64" or arch == "armv7": time.sleep(10) else: time.sleep(1) process.SendAsyncInterrupt() self.assertTrue( self.wait_for_stop(process, listener), "Check that process is paused" ) inferior_set_up = process.GetTarget().CreateValueFromExpression( "threads_up_and_running", "threads_up_and_running" ) if inferior_set_up.IsValid() and inferior_set_up.GetValueAsSigned() == 1: retry = 0 else: process.Continue() retry = retry - 1 return inferior_set_up # Listen to the process events until we get an event saying that the process is # running. Retry up to five times in case we get other events that are not # what we're looking for. def wait_for_running(self, process, listener): retry_count = 5 if process.GetState() == lldb.eStateRunning: return True while retry_count > 0: event = lldb.SBEvent() listener.WaitForEvent(2, event) if event.GetType() == lldb.SBProcess.eBroadcastBitStateChanged: if process.GetState() == lldb.eStateRunning: return True retry_count = retry_count - 1 return False # Listen to the process events until we get an event saying the process is # stopped. Retry up to five times in case we get other events that we are # not looking for. def wait_for_stop(self, process, listener): retry_count = 5 if ( process.GetState() == lldb.eStateStopped or process.GetState() == lldb.eStateCrashed or process.GetState() == lldb.eStateDetached or process.GetState() == lldb.eStateExited ): return True while retry_count > 0: event = lldb.SBEvent() listener.WaitForEvent(2, event) if event.GetType() == lldb.SBProcess.eBroadcastBitStateChanged: if ( process.GetState() == lldb.eStateStopped or process.GetState() == lldb.eStateCrashed or process.GetState() == lldb.eStateDetached or process.GetState() == lldb.eStateExited ): return True if ( process.GetState() == lldb.eStateCrashed or process.GetState() == lldb.eStateDetached or process.GetState() == lldb.eStateExited ): return False retry_count = retry_count - 1 return False def check_number_of_threads(self, process): self.assertEqual( process.GetNumThreads(), 3, "Check that the process has three threads when sitting at the stopper() breakpoint", ) def check_expected_threads_present(self, main_thread, second_thread, third_thread): self.assertTrue( main_thread.IsValid() and second_thread.IsValid() and third_thread.IsValid(), "Got all three expected threads", )