xref: /llvm-project/lldb/test/API/functionalities/thread/exit_during_step/TestExitDuringStep.py (revision 4cc8f2a017c76af25234afc7c380550e9c93135c)
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