1""" 2Test number of threads. 3""" 4 5 6import lldb 7from lldbsuite.test.decorators import * 8from lldbsuite.test.lldbtest import * 9from lldbsuite.test import lldbutil 10 11 12class ExitDuringStepTestCase(TestBase): 13 @skipIfWindows # This is flakey on Windows: llvm.org/pr38373 14 def test(self): 15 """Test thread exit during step handling.""" 16 self.build() 17 self.exit_during_step_base( 18 "thread step-inst -m all-threads", "stop reason = instruction step", True 19 ) 20 21 @skipIfWindows # This is flakey on Windows: llvm.org/pr38373 22 def test_step_over(self): 23 """Test thread exit during step-over handling.""" 24 self.build() 25 self.exit_during_step_base( 26 "thread step-over -m all-threads", "stop reason = step over", False 27 ) 28 29 @skipIfWindows # This is flakey on Windows: llvm.org/pr38373 30 def test_step_in(self): 31 """Test thread exit during step-in handling.""" 32 self.build() 33 self.exit_during_step_base( 34 "thread step-in -m all-threads", "stop reason = step in", False 35 ) 36 37 def setUp(self): 38 # Call super's setUp(). 39 TestBase.setUp(self) 40 # Find the line numbers to break and continue. 41 self.breakpoint = line_number("main.cpp", "// Set breakpoint here") 42 self.continuepoint = line_number("main.cpp", "// Continue from here") 43 44 def exit_during_step_base(self, step_cmd, step_stop_reason, by_instruction): 45 """Test thread exit during step handling.""" 46 exe = self.getBuildArtifact("a.out") 47 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 48 49 # This should create a breakpoint in the main thread. 50 self.bp_num = lldbutil.run_break_set_by_file_and_line( 51 self, "main.cpp", self.breakpoint, num_expected_locations=1 52 ) 53 54 # The breakpoint list should show 1 location. 55 self.expect( 56 "breakpoint list -f", 57 "Breakpoint location shown correctly", 58 substrs=[ 59 "1: file = 'main.cpp', line = %d, exact_match = 0, locations = 1" 60 % self.breakpoint 61 ], 62 ) 63 64 # Run the program. 65 self.runCmd("run", RUN_SUCCEEDED) 66 67 # The stop reason of the thread should be breakpoint. 68 self.expect( 69 "thread list", 70 STOPPED_DUE_TO_BREAKPOINT, 71 substrs=["stopped", "stop reason = breakpoint"], 72 ) 73 74 # Get the target process 75 target = self.dbg.GetSelectedTarget() 76 process = target.GetProcess() 77 78 num_threads = process.GetNumThreads() 79 # Make sure we see all three threads 80 self.assertGreaterEqual( 81 num_threads, 82 3, 83 "Number of expected threads and actual threads do not match.", 84 ) 85 86 stepping_thread = lldbutil.get_one_thread_stopped_at_breakpoint_id( 87 process, self.bp_num 88 ) 89 self.assertIsNotNone( 90 stepping_thread, "Could not find a thread stopped at the breakpoint" 91 ) 92 93 current_line = self.breakpoint 94 stepping_frame = stepping_thread.GetFrameAtIndex(0) 95 self.assertEqual( 96 current_line, 97 stepping_frame.GetLineEntry().GetLine(), 98 "Starting line for stepping doesn't match breakpoint line.", 99 ) 100 101 # Keep stepping until we've reached our designated continue point 102 while current_line != self.continuepoint: 103 # Since we're using the command interpreter to issue the thread command 104 # (on the selected thread) we need to ensure the selected thread is the 105 # stepping thread. 106 if stepping_thread != process.GetSelectedThread(): 107 process.SetSelectedThread(stepping_thread) 108 109 self.runCmd(step_cmd) 110 111 frame = stepping_thread.GetFrameAtIndex(0) 112 113 current_line = frame.GetLineEntry().GetLine() 114 115 if by_instruction and current_line == 0: 116 continue 117 118 self.assertGreaterEqual( 119 current_line, 120 self.breakpoint, 121 "Stepped to unexpected line, " + str(current_line), 122 ) 123 self.assertLessEqual( 124 current_line, 125 self.continuepoint, 126 "Stepped to unexpected line, " + str(current_line), 127 ) 128 129 self.runCmd("thread list") 130 131 # Update the number of threads 132 new_num_threads = process.GetNumThreads() 133 134 # Check to see that we reduced the number of threads as expected 135 self.assertEqual( 136 new_num_threads, 137 num_threads - 1, 138 "Number of threads did not reduce by 1 after thread exit.", 139 ) 140 141 self.expect( 142 "thread list", 143 "Process state is stopped due to step", 144 substrs=["stopped", step_stop_reason], 145 ) 146 147 # Run to completion 148 self.runCmd("continue") 149 150 # At this point, the inferior process should have exited. 151 self.assertState(process.GetState(), lldb.eStateExited, PROCESS_EXITED) 152