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