1"""
2Test breakpoint ignore count features.
3"""
4
5
6
7import lldb
8from lldbsuite.test.decorators import *
9from lldbsuite.test.lldbtest import *
10from lldbsuite.test import lldbutil
11
12
13class BreakpointIgnoreCountTestCase(TestBase):
14
15    @skipIfWindows # This test will hang on windows llvm.org/pr21753
16    def test_with_run_command(self):
17        """Exercise breakpoint ignore count with 'breakpoint set -i <count>'."""
18        self.build()
19        self.breakpoint_ignore_count()
20
21    @add_test_categories(['pyapi'])
22    @skipIfWindows # This test will hang on windows llvm.org/pr21753
23    def test_with_python_api(self):
24        """Use Python APIs to set breakpoint ignore count."""
25        self.build()
26        self.breakpoint_ignore_count_python()
27
28    @skipIfWindows # This test will hang on windows llvm.org/pr21753
29    def test_ignore_vrs_condition_bkpt(self):
30        self.build()
31        self.ignore_vrs_condition(False)
32
33    @skipIfWindows # This test will hang on windows llvm.org/pr21753
34    def test_ignore_vrs_condition_loc(self):
35        self.build()
36        self.ignore_vrs_condition(True)
37
38    def setUp(self):
39        # Call super's setUp().
40        TestBase.setUp(self)
41        # Find the line number to of function 'c'.
42        self.stop_in_main = "Stop here at start of main"
43        self.line1 = line_number(
44            'main.c', '// Find the line number of function "c" here.')
45        self.line2 = line_number(
46            'main.c', '// b(2) -> c(2) Find the call site of b(2).')
47        self.line3 = line_number(
48            'main.c', '// a(3) -> c(3) Find the call site of c(3).')
49        self.line4 = line_number(
50            'main.c', '// a(3) -> c(3) Find the call site of a(3).')
51        self.line5 = line_number(
52            'main.c', '// Find the call site of c in main.')
53
54    def breakpoint_ignore_count(self):
55        """Exercise breakpoint ignore count with 'breakpoint set -i <count>'."""
56        exe = self.getBuildArtifact("a.out")
57        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
58
59        # Create a breakpoint in main.c at line1.
60        lldbutil.run_break_set_by_file_and_line(
61            self,
62            'main.c',
63            self.line1,
64            extra_options='-i 1',
65            num_expected_locations=1,
66            loc_exact=True)
67
68        # Now run the program.
69        self.runCmd("run", RUN_SUCCEEDED)
70
71        # The process should be stopped at this point.
72        self.expect("process status", PROCESS_STOPPED,
73                    patterns=['Process .* stopped'])
74
75        # Also check the hit count, which should be 2, due to ignore count of
76        # 1.
77        lldbutil.check_breakpoint(self, bpno = 1, expected_hit_count = 2)
78
79        # The frame #0 should correspond to main.c:37, the executable statement
80        # in function name 'c'.  And frame #2 should point to main.c:45.
81        self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT_IGNORE_COUNT,
82                    #substrs = ["stop reason = breakpoint"],
83                    patterns=["frame #0.*main.c:%d" % self.line1,
84                              "frame #2.*main.c:%d" % self.line2])
85
86        # continue -i 1 is the same as setting the ignore count to 1 again, try that:
87        # Now run the program.
88        self.runCmd("process continue -i 1", RUN_SUCCEEDED)
89
90        # The process should be stopped at this point.
91        self.expect("process status", PROCESS_STOPPED,
92                    patterns=['Process .* stopped'])
93
94        # Also check the hit count, which should be 2, due to ignore count of
95        # 1.
96        lldbutil.check_breakpoint(self, bpno = 1, expected_hit_count = 4)
97
98        # The frame #0 should correspond to main.c:37, the executable statement
99        # in function name 'c'.  And frame #2 should point to main.c:45.
100        self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT_IGNORE_COUNT,
101                    #substrs = ["stop reason = breakpoint"],
102                    patterns=["frame #0.*main.c:%d" % self.line1,
103                              "frame #1.*main.c:%d" % self.line5])
104
105    def breakpoint_ignore_count_python(self):
106        """Use Python APIs to set breakpoint ignore count."""
107        target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(self,
108                                                                          self.stop_in_main,
109                                                                          lldb.SBFileSpec("main.c"))
110        # Now create a breakpoint on main.c by name 'c'.
111        breakpoint = target.BreakpointCreateByName('c', 'a.out')
112        self.assertTrue(breakpoint and
113                        breakpoint.GetNumLocations() == 1,
114                        VALID_BREAKPOINT)
115
116        # Get the breakpoint location from breakpoint after we verified that,
117        # indeed, it has one location.
118        location = breakpoint.GetLocationAtIndex(0)
119        self.assertTrue(location and
120                        location.IsEnabled(),
121                        VALID_BREAKPOINT_LOCATION)
122
123        # Set the ignore count on the breakpoint location.
124        location.SetIgnoreCount(2)
125        self.assertEqual(location.GetIgnoreCount(), 2,
126                        "SetIgnoreCount() works correctly")
127
128        # Now continue and hit our breakpoint on c:
129        process.Continue()
130
131        # Frame#0 should be on main.c:37, frame#1 should be on main.c:25, and
132        # frame#2 should be on main.c:48.
133        # lldbutil.print_stacktraces(process)
134        from lldbsuite.test.lldbutil import get_stopped_thread
135        thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint)
136        self.assertTrue(
137            thread.IsValid(),
138            "There should be a thread stopped due to breakpoint")
139        frame0 = thread.GetFrameAtIndex(0)
140        frame1 = thread.GetFrameAtIndex(1)
141        frame2 = thread.GetFrameAtIndex(2)
142        self.assertTrue(frame0.GetLineEntry().GetLine() == self.line1 and
143                        frame1.GetLineEntry().GetLine() == self.line3 and
144                        frame2.GetLineEntry().GetLine() == self.line4,
145                        STOPPED_DUE_TO_BREAKPOINT_IGNORE_COUNT)
146
147        # The hit count for the breakpoint should be 3.
148        self.assertEqual(breakpoint.GetHitCount(), 3)
149
150    def ignore_vrs_condition(self, use_location):
151        main_spec = lldb.SBFileSpec("main.c")
152        target, process, _ , _ = lldbutil.run_to_source_breakpoint(self,
153                                                                   self.stop_in_main,
154                                                                   main_spec)
155
156        # Now make a breakpoint on the loop, and set a condition and ignore count.
157        # Make sure that the condition fails don't count against the ignore count.
158        bkpt = target.BreakpointCreateBySourceRegex("Set a breakpoint here, with i", main_spec)
159        self.assertEqual(bkpt.GetNumLocations(), 1, "Wrong number of locations")
160
161        if use_location:
162            loc = bkpt.location[0]
163            self.assertTrue(loc.IsValid(), "Got a valid location")
164            loc.SetIgnoreCount(2)
165            loc.SetCondition("i >= 3")
166        else:
167            bkpt.SetIgnoreCount(2)
168            bkpt.SetCondition("i >= 3")
169
170        threads = lldbutil.continue_to_breakpoint(process, bkpt)
171        self.assertEqual(len(threads), 1, "Hit the breakpoint")
172        var = threads[0].frame[0].FindVariable("i")
173        self.assertTrue(var.IsValid(), "Didn't find the i variable")
174        val = var.GetValueAsUnsigned(10000)
175        self.assertNotEqual(val, 10000, "Got the fail value for i")
176        self.assertEqual(val, 5, "We didn't stop the right number of times")
177        self.assertEqual(bkpt.GetHitCount(), 3, "Hit count is not right")
178