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