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