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