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