1"""
2Test number of threads.
3"""
4
5import os, time
6import unittest2
7import lldb
8from lldbtest import *
9import lldbutil
10
11class ExitDuringStepTestCase(TestBase):
12
13    mydir = os.path.join("functionalities", "thread", "exit_during_step")
14
15    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
16    @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained
17    @dsym_test
18    def test_with_dsym(self):
19        """Test thread exit during step handling."""
20        self.buildDsym(dictionary=self.getBuildFlags())
21        self.exit_during_step_inst_test()
22
23    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
24    @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained
25    @dsym_test
26    def test_step_over_with_dsym(self):
27        """Test thread exit during step-over handling."""
28        self.buildDsym(dictionary=self.getBuildFlags())
29        self.exit_during_step_over_test()
30
31    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
32    @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained
33    @dsym_test
34    def test_step_in_with_dsym(self):
35        """Test thread exit during step-in handling."""
36        self.buildDsym(dictionary=self.getBuildFlags())
37        self.exit_during_step_in_test()
38
39    @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained
40    @expectedFailureFreeBSD("llvm.org/pr16696") # threaded inferior not yet implemented on FreeBSD
41    @dwarf_test
42    def test_with_dwarf(self):
43        """Test thread exit during step handling."""
44        self.buildDwarf(dictionary=self.getBuildFlags())
45        self.exit_during_step_inst_test()
46
47    @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained
48    @expectedFailureFreeBSD("llvm.org/pr16696") # threaded inferior not yet implemented on FreeBSD
49    @dwarf_test
50    def test_step_over_with_dwarf(self):
51        """Test thread exit during step-over handling."""
52        self.buildDwarf(dictionary=self.getBuildFlags())
53        self.exit_during_step_over_test()
54
55    @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained
56    @expectedFailureFreeBSD("llvm.org/pr16696") # threaded inferior not yet implemented on FreeBSD
57    @dwarf_test
58    def test_step_in_with_dwarf(self):
59        """Test thread exit during step-in handling."""
60        self.buildDwarf(dictionary=self.getBuildFlags())
61        self.exit_during_step_in_test()
62
63    def setUp(self):
64        # Call super's setUp().
65        TestBase.setUp(self)
66        # Find the line numbers to break and continue.
67        self.breakpoint = line_number('main.cpp', '// Set breakpoint here')
68        self.continuepoint = line_number('main.cpp', '// Continue from here')
69
70    def exit_during_step_inst_test(self):
71        """Test thread exit while using step-inst."""
72        self.exit_during_step_base("thread step-inst -m all-threads", 'stop reason = instruction step')
73
74    def exit_during_step_over_test(self):
75        """Test thread exit while using step-over."""
76        self.exit_during_step_base("thread step-over -m all-threads", 'stop reason = step over')
77
78    def exit_during_step_in_test(self):
79        """Test thread exit while using step-in."""
80        self.exit_during_step_base("thread step-in -m all-threads", 'stop reason = step in')
81
82    def exit_during_step_base(self, step_cmd, step_stop_reason):
83        """Test thread exit during step handling."""
84        exe = os.path.join(os.getcwd(), "a.out")
85        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
86
87        # This should create a breakpoint in the main thread.
88        lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.breakpoint, num_expected_locations=1)
89
90        # The breakpoint list should show 1 location.
91        self.expect("breakpoint list -f", "Breakpoint location shown correctly",
92            substrs = ["1: file = 'main.cpp', line = %d, locations = 1" % self.breakpoint])
93
94        # Run the program.
95        self.runCmd("run", RUN_SUCCEEDED)
96
97        # The stop reason of the thread should be breakpoint.
98        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
99            substrs = ['stopped',
100                       'stop reason = breakpoint'])
101
102        # Get the target process
103        target = self.dbg.GetSelectedTarget()
104        process = target.GetProcess()
105
106        # Get the number of threads
107        num_threads = process.GetNumThreads()
108
109        # Make sure we see all three threads
110        self.assertTrue(num_threads == 3, 'Number of expected threads and actual threads do not match.')
111
112        # Get the thread objects
113        thread1 = process.GetThreadAtIndex(0)
114        thread2 = process.GetThreadAtIndex(1)
115        thread3 = process.GetThreadAtIndex(2)
116
117        # Make sure all threads are stopped
118        self.assertTrue(thread1.IsStopped(), "Thread 1 didn't stop during breakpoint")
119        self.assertTrue(thread2.IsStopped(), "Thread 2 didn't stop during breakpoint")
120        self.assertTrue(thread3.IsStopped(), "Thread 3 didn't stop during breakpoint")
121
122        # Keep stepping until we've reached our designated continue point
123        stepping_thread = process.GetSelectedThread()
124        current_line = self.breakpoint
125        stepping_frame = stepping_thread.GetFrameAtIndex(0)
126        self.assertTrue(current_line == stepping_frame.GetLineEntry().GetLine(), "Starting line for stepping doesn't match breakpoint line.")
127        while current_line != self.continuepoint:
128            self.runCmd(step_cmd)
129
130            if stepping_thread != process.GetSelectedThread():
131                process.SetSelectedThread(stepping_thread)
132
133            frame = stepping_thread.GetFrameAtIndex(0)
134
135            current_line = frame.GetLineEntry().GetLine()
136
137            self.assertTrue(current_line >= self.breakpoint, "Stepped to unexpected line, " + str(current_line))
138            self.assertTrue(current_line <= self.continuepoint, "Stepped to unexpected line, " + str(current_line))
139
140        self.runCmd("thread list")
141
142        # Update the number of threads
143        num_threads = process.GetNumThreads()
144
145        # Check to see that we reduced the number of threads as expected
146        self.assertTrue(num_threads == 2, 'Number of expected threads and actual threads do not match after thread exit.')
147
148        self.expect("thread list", 'Process state is stopped due to step',
149                substrs = ['stopped',
150                           step_stop_reason])
151
152        # Run to completion
153        self.runCmd("continue")
154
155        # At this point, the inferior process should have exited.
156        self.assertTrue(process.GetState() == lldb.eStateExited, PROCESS_EXITED)
157
158if __name__ == '__main__':
159    import atexit
160    lldb.SBDebugger.Initialize()
161    atexit.register(lambda: lldb.SBDebugger.Terminate())
162    unittest2.main()
163