1"""
2Test that lldb watchpoint works for multiple threads.
3"""
4
5from __future__ import print_function
6
7
8import re
9import lldb
10from lldbsuite.test.decorators import *
11from lldbsuite.test.lldbtest import *
12from lldbsuite.test import lldbutil
13
14
15class WatchpointForMultipleThreadsTestCase(TestBase):
16
17    mydir = TestBase.compute_mydir(__file__)
18    NO_DEBUG_INFO_TESTCASE = True
19    main_spec = lldb.SBFileSpec("main.cpp", False)
20
21    @skipIfWindows # This test is flaky on Windows
22    def test_watchpoint_before_thread_start(self):
23        """Test that we can hit a watchpoint we set before starting another thread"""
24        self.do_watchpoint_test("Before running the thread")
25
26    def test_watchpoint_after_thread_launch(self):
27        """Test that we can hit a watchpoint we set after launching another thread"""
28        self.do_watchpoint_test("After launching the thread")
29
30    def test_watchpoint_after_thread_start(self):
31        """Test that we can hit a watchpoint we set after another thread starts"""
32        self.do_watchpoint_test("After running the thread")
33
34    def do_watchpoint_test(self, line):
35        self.build()
36        lldbutil.run_to_source_breakpoint(self, line, self.main_spec)
37
38        # Now let's set a write-type watchpoint for variable 'g_val'.
39        self.expect(
40            "watchpoint set variable -w write g_val",
41            WATCHPOINT_CREATED,
42            substrs=[
43                'Watchpoint created',
44                'size = 4',
45                'type = w'])
46
47        # Use the '-v' option to do verbose listing of the watchpoint.
48        # The hit count should be 0 initially.
49        self.expect("watchpoint list -v",
50                    substrs=['hit_count = 0'])
51
52        self.runCmd("process continue")
53
54        self.runCmd("thread list")
55        if "stop reason = watchpoint" in self.res.GetOutput():
56            # Good, we verified that the watchpoint works!
57            self.runCmd("thread backtrace all")
58        else:
59            self.fail("The stop reason should be either break or watchpoint")
60
61        # Use the '-v' option to do verbose listing of the watchpoint.
62        # The hit count should now be 1.
63        self.expect("watchpoint list -v",
64                    substrs=['hit_count = 1'])
65
66    def test_watchpoint_multiple_threads_wp_set_and_then_delete(self):
67        """Test that lldb watchpoint works for multiple threads, and after the watchpoint is deleted, the watchpoint event should no longer fires."""
68        self.build()
69        self.setTearDownCleanup()
70
71        lldbutil.run_to_source_breakpoint(self, "After running the thread", self.main_spec)
72
73        # Now let's set a write-type watchpoint for variable 'g_val'.
74        self.expect(
75            "watchpoint set variable -w write g_val",
76            WATCHPOINT_CREATED,
77            substrs=[
78                'Watchpoint created',
79                'size = 4',
80                'type = w'])
81
82        # Use the '-v' option to do verbose listing of the watchpoint.
83        # The hit count should be 0 initially.
84        self.expect("watchpoint list -v",
85                    substrs=['hit_count = 0'])
86
87        watchpoint_stops = 0
88        while True:
89            self.runCmd("process continue")
90            self.runCmd("process status")
91            if re.search("Process .* exited", self.res.GetOutput()):
92                # Great, we are done with this test!
93                break
94
95            self.runCmd("thread list")
96            if "stop reason = watchpoint" in self.res.GetOutput():
97                self.runCmd("thread backtrace all")
98                watchpoint_stops += 1
99                if watchpoint_stops > 1:
100                    self.fail(
101                        "Watchpoint hits not supposed to exceed 1 by design!")
102                # Good, we verified that the watchpoint works!  Now delete the
103                # watchpoint.
104                if self.TraceOn():
105                    print(
106                        "watchpoint_stops=%d at the moment we delete the watchpoint" %
107                        watchpoint_stops)
108                self.runCmd("watchpoint delete 1")
109                self.expect("watchpoint list -v",
110                            substrs=['No watchpoints currently set.'])
111                continue
112            else:
113                self.fail("The stop reason should be either break or watchpoint")
114