1"""
2Test hardware breakpoints for multiple threads.
3"""
4
5
6
7import lldb
8from lldbsuite.test.decorators import *
9from lldbsuite.test.lldbtest import *
10from lldbsuite.test import lldbutil
11
12from functionalities.breakpoint.hardware_breakpoints.base import *
13
14class HardwareBreakpointMultiThreadTestCase(HardwareBreakpointTestBase):
15    mydir = TestBase.compute_mydir(__file__)
16
17    def does_not_support_hw_breakpoints(self):
18        return not super().supports_hw_breakpoints()
19
20    @skipIfOutOfTreeDebugserver
21    @skipTestIfFn(does_not_support_hw_breakpoints)
22    def test_hw_break_set_delete_multi_thread_macos(self):
23        self.build()
24        self.setTearDownCleanup()
25        self.break_multi_thread('delete')
26
27    @skipIfOutOfTreeDebugserver
28    @skipTestIfFn(does_not_support_hw_breakpoints)
29    def test_hw_break_set_disable_multi_thread_macos(self):
30        self.build()
31        self.setTearDownCleanup()
32        self.break_multi_thread('disable')
33
34    def setUp(self):
35        # Call super's setUp().
36        TestBase.setUp(self)
37        # Our simple source filename.
38        self.source = 'main.cpp'
39        # Find the line number to break inside main().
40        self.first_stop = line_number(
41            self.source, 'Starting thread creation with hardware breakpoint set')
42
43    def break_multi_thread(self, removal_type):
44        """Test that lldb hardware breakpoints work for multiple threads."""
45        self.runCmd("file " + self.getBuildArtifact("a.out"),
46                    CURRENT_EXECUTABLE_SET)
47
48        # Stop in main before creating any threads.
49        lldbutil.run_break_set_by_file_and_line(
50            self, None, self.first_stop, num_expected_locations=1)
51
52        # Run the program.
53        self.runCmd("run", RUN_SUCCEEDED)
54
55        # We should be stopped again due to the breakpoint.
56        # The stop reason of the thread should be breakpoint.
57        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
58                    substrs=['stopped', 'stop reason = breakpoint'])
59
60        # Now set a hardware breakpoint in thread function.
61        self.expect("breakpoint set -b hw_break_function --hardware",
62            substrs=[
63                'Breakpoint',
64                'hw_break_function',
65                'address = 0x'])
66
67        # We should stop in hw_break_function function for 4 threads.
68        count = 0
69
70        while count < 2 :
71
72            self.runCmd("process continue")
73
74            # We should be stopped in hw_break_function
75            # The stop reason of the thread should be breakpoint.
76            self.expect(
77                "thread list",
78                STOPPED_DUE_TO_BREAKPOINT,
79                substrs=[
80                    'hw_break_function',
81                    'stop reason = breakpoint',
82                ])
83
84            # Continue the loop and test that we are stopped 4 times.
85            count += 1
86
87        # Check the breakpoint list.
88        self.expect("breakpoint list", substrs=['hw_break_function', 'hardware'])
89        self.expect("breakpoint list -v", substrs=['function = hw_break_function', 'hardware = true'])
90
91        if removal_type == 'delete':
92            self.runCmd("settings set auto-confirm true")
93
94            # Now 'breakpoint delete' should just work fine without confirmation
95            # prompt from the command interpreter.
96            self.expect("breakpoint delete",
97                        startstr="All breakpoints removed")
98
99            # Restore the original setting of auto-confirm.
100            self.runCmd("settings clear auto-confirm")
101
102        elif removal_type == 'disable':
103            self.expect("breakpoint disable",
104                        startstr="All breakpoints disabled.")
105
106        # Continue. Program should exit without stopping anywhere.
107        self.runCmd("process continue")
108
109        # Process should have stopped and exited with status = 0
110        self.expect("process status", PROCESS_STOPPED,
111                    patterns=['Process .* exited with status = 0'])
112