199451b44SJordan Rupprecht"""
299451b44SJordan RupprechtTest that lldb watchpoint works for multiple threads.
399451b44SJordan Rupprecht"""
499451b44SJordan Rupprecht
599451b44SJordan Rupprechtfrom __future__ import print_function
699451b44SJordan Rupprecht
799451b44SJordan Rupprecht
899451b44SJordan Rupprechtimport re
999451b44SJordan Rupprechtimport lldb
1099451b44SJordan Rupprechtfrom lldbsuite.test.decorators import *
1199451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import *
1299451b44SJordan Rupprechtfrom lldbsuite.test import lldbutil
1399451b44SJordan Rupprecht
1499451b44SJordan Rupprecht
1599451b44SJordan Rupprechtclass WatchpointForMultipleThreadsTestCase(TestBase):
1699451b44SJordan Rupprecht    NO_DEBUG_INFO_TESTCASE = True
1799451b44SJordan Rupprecht    main_spec = lldb.SBFileSpec("main.cpp", False)
1899451b44SJordan Rupprecht
198fec756cSStella Stamenova    @skipIfWindows # This test is flaky on Windows
2099451b44SJordan Rupprecht    def test_watchpoint_before_thread_start(self):
2199451b44SJordan Rupprecht        """Test that we can hit a watchpoint we set before starting another thread"""
2299451b44SJordan Rupprecht        self.do_watchpoint_test("Before running the thread")
2399451b44SJordan Rupprecht
24*df13239cSMuhammad Omair Javaid    @skipIfWindows # This test is flaky on Windows
257e2ef84fSMichał Górny    def test_watchpoint_after_thread_launch(self):
267e2ef84fSMichał Górny        """Test that we can hit a watchpoint we set after launching another thread"""
277e2ef84fSMichał Górny        self.do_watchpoint_test("After launching the thread")
287e2ef84fSMichał Górny
2999451b44SJordan Rupprecht    def test_watchpoint_after_thread_start(self):
307e2ef84fSMichał Górny        """Test that we can hit a watchpoint we set after another thread starts"""
3199451b44SJordan Rupprecht        self.do_watchpoint_test("After running the thread")
3299451b44SJordan Rupprecht
3399451b44SJordan Rupprecht    def do_watchpoint_test(self, line):
3499451b44SJordan Rupprecht        self.build()
3599451b44SJordan Rupprecht        lldbutil.run_to_source_breakpoint(self, line, self.main_spec)
3699451b44SJordan Rupprecht
3799451b44SJordan Rupprecht        # Now let's set a write-type watchpoint for variable 'g_val'.
3899451b44SJordan Rupprecht        self.expect(
3999451b44SJordan Rupprecht            "watchpoint set variable -w write g_val",
4099451b44SJordan Rupprecht            WATCHPOINT_CREATED,
4199451b44SJordan Rupprecht            substrs=[
4299451b44SJordan Rupprecht                'Watchpoint created',
4399451b44SJordan Rupprecht                'size = 4',
4499451b44SJordan Rupprecht                'type = w'])
4599451b44SJordan Rupprecht
4699451b44SJordan Rupprecht        # Use the '-v' option to do verbose listing of the watchpoint.
4799451b44SJordan Rupprecht        # The hit count should be 0 initially.
4899451b44SJordan Rupprecht        self.expect("watchpoint list -v",
4999451b44SJordan Rupprecht                    substrs=['hit_count = 0'])
5099451b44SJordan Rupprecht
5199451b44SJordan Rupprecht        self.runCmd("process continue")
5299451b44SJordan Rupprecht
5399451b44SJordan Rupprecht        self.runCmd("thread list")
5499451b44SJordan Rupprecht        if "stop reason = watchpoint" in self.res.GetOutput():
5599451b44SJordan Rupprecht            # Good, we verified that the watchpoint works!
5699451b44SJordan Rupprecht            self.runCmd("thread backtrace all")
5799451b44SJordan Rupprecht        else:
5899451b44SJordan Rupprecht            self.fail("The stop reason should be either break or watchpoint")
5999451b44SJordan Rupprecht
6099451b44SJordan Rupprecht        # Use the '-v' option to do verbose listing of the watchpoint.
6199451b44SJordan Rupprecht        # The hit count should now be 1.
6299451b44SJordan Rupprecht        self.expect("watchpoint list -v",
6399451b44SJordan Rupprecht                    substrs=['hit_count = 1'])
6499451b44SJordan Rupprecht
6599451b44SJordan Rupprecht    def test_watchpoint_multiple_threads_wp_set_and_then_delete(self):
6699451b44SJordan Rupprecht        """Test that lldb watchpoint works for multiple threads, and after the watchpoint is deleted, the watchpoint event should no longer fires."""
6799451b44SJordan Rupprecht        self.build()
6899451b44SJordan Rupprecht        self.setTearDownCleanup()
6999451b44SJordan Rupprecht
7099451b44SJordan Rupprecht        lldbutil.run_to_source_breakpoint(self, "After running the thread", self.main_spec)
7199451b44SJordan Rupprecht
7299451b44SJordan Rupprecht        # Now let's set a write-type watchpoint for variable 'g_val'.
7399451b44SJordan Rupprecht        self.expect(
7499451b44SJordan Rupprecht            "watchpoint set variable -w write g_val",
7599451b44SJordan Rupprecht            WATCHPOINT_CREATED,
7699451b44SJordan Rupprecht            substrs=[
7799451b44SJordan Rupprecht                'Watchpoint created',
7899451b44SJordan Rupprecht                'size = 4',
7999451b44SJordan Rupprecht                'type = w'])
8099451b44SJordan Rupprecht
8199451b44SJordan Rupprecht        # Use the '-v' option to do verbose listing of the watchpoint.
8299451b44SJordan Rupprecht        # The hit count should be 0 initially.
8399451b44SJordan Rupprecht        self.expect("watchpoint list -v",
8499451b44SJordan Rupprecht                    substrs=['hit_count = 0'])
8599451b44SJordan Rupprecht
8699451b44SJordan Rupprecht        watchpoint_stops = 0
8799451b44SJordan Rupprecht        while True:
8899451b44SJordan Rupprecht            self.runCmd("process continue")
8999451b44SJordan Rupprecht            self.runCmd("process status")
9099451b44SJordan Rupprecht            if re.search("Process .* exited", self.res.GetOutput()):
9199451b44SJordan Rupprecht                # Great, we are done with this test!
9299451b44SJordan Rupprecht                break
9399451b44SJordan Rupprecht
9499451b44SJordan Rupprecht            self.runCmd("thread list")
9599451b44SJordan Rupprecht            if "stop reason = watchpoint" in self.res.GetOutput():
9699451b44SJordan Rupprecht                self.runCmd("thread backtrace all")
9799451b44SJordan Rupprecht                watchpoint_stops += 1
9899451b44SJordan Rupprecht                if watchpoint_stops > 1:
9999451b44SJordan Rupprecht                    self.fail(
10099451b44SJordan Rupprecht                        "Watchpoint hits not supposed to exceed 1 by design!")
10199451b44SJordan Rupprecht                # Good, we verified that the watchpoint works!  Now delete the
10299451b44SJordan Rupprecht                # watchpoint.
10399451b44SJordan Rupprecht                if self.TraceOn():
10499451b44SJordan Rupprecht                    print(
10599451b44SJordan Rupprecht                        "watchpoint_stops=%d at the moment we delete the watchpoint" %
10699451b44SJordan Rupprecht                        watchpoint_stops)
10799451b44SJordan Rupprecht                self.runCmd("watchpoint delete 1")
10899451b44SJordan Rupprecht                self.expect("watchpoint list -v",
10999451b44SJordan Rupprecht                            substrs=['No watchpoints currently set.'])
11099451b44SJordan Rupprecht                continue
11199451b44SJordan Rupprecht            else:
11299451b44SJordan Rupprecht                self.fail("The stop reason should be either break or watchpoint")
113