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