1"""
2Test that breakpoints do not affect stepping.
3Check for correct StopReason when stepping to the line with breakpoint
4which should be eStopReasonBreakpoint in general,
5and eStopReasonPlanComplete when breakpoint's condition fails.
6"""
7
8
9import lldb
10from lldbsuite.test.decorators import *
11from lldbsuite.test.lldbtest import *
12from lldbsuite.test import lldbutil
13
14
15class StepOverBreakpointsTestCase(TestBase):
16    def setUp(self):
17        TestBase.setUp(self)
18
19        self.build()
20        exe = self.getBuildArtifact("a.out")
21        src = lldb.SBFileSpec("main.cpp")
22
23        # Create a target by the debugger.
24        self.target = self.dbg.CreateTarget(exe)
25        self.assertTrue(self.target, VALID_TARGET)
26
27        # Setup four breakpoints, two of them with false condition
28        self.line1 = line_number("main.cpp", "breakpoint_1")
29        self.line4 = line_number("main.cpp", "breakpoint_4")
30
31        self.breakpoint1 = self.target.BreakpointCreateByLocation(src, self.line1)
32        self.assertTrue(
33            self.breakpoint1 and self.breakpoint1.GetNumLocations() == 1,
34            VALID_BREAKPOINT,
35        )
36
37        self.breakpoint2 = self.target.BreakpointCreateBySourceRegex(
38            "breakpoint_2", src
39        )
40        self.breakpoint2.GetLocationAtIndex(0).SetCondition("false")
41
42        self.breakpoint3 = self.target.BreakpointCreateBySourceRegex(
43            "breakpoint_3", src
44        )
45        self.breakpoint3.GetLocationAtIndex(0).SetCondition("false")
46
47        self.breakpoint4 = self.target.BreakpointCreateByLocation(src, self.line4)
48
49        # Start debugging
50        self.process = self.target.LaunchSimple(
51            None, None, self.get_process_working_directory()
52        )
53        self.assertIsNotNone(self.process, PROCESS_IS_VALID)
54        self.thread = lldbutil.get_one_thread_stopped_at_breakpoint(
55            self.process, self.breakpoint1
56        )
57        self.assertIsNotNone(self.thread, "Didn't stop at breakpoint 1.")
58
59    def test_step_instruction(self):
60        # Count instructions between breakpoint_1 and breakpoint_4
61        contextList = self.target.FindFunctions("main", lldb.eFunctionNameTypeAuto)
62        self.assertEqual(contextList.GetSize(), 1)
63        symbolContext = contextList.GetContextAtIndex(0)
64        function = symbolContext.GetFunction()
65        self.assertTrue(function)
66        instructions = function.GetInstructions(self.target)
67        addr_1 = self.breakpoint1.GetLocationAtIndex(0).GetAddress()
68        addr_4 = self.breakpoint4.GetLocationAtIndex(0).GetAddress()
69
70        # if third argument is true then the count will be the number of
71        # instructions on which a breakpoint can be set.
72        # start = addr_1, end = addr_4, canSetBreakpoint = True
73        steps_expected = instructions.GetInstructionsCount(addr_1, addr_4, True)
74        step_count = 0
75        # Step from breakpoint_1 to breakpoint_4
76        while True:
77            self.thread.StepInstruction(True)
78            step_count = step_count + 1
79            self.assertState(self.process.GetState(), lldb.eStateStopped)
80            self.assertTrue(
81                self.thread.GetStopReason() == lldb.eStopReasonPlanComplete
82                or self.thread.GetStopReason() == lldb.eStopReasonBreakpoint
83            )
84            if self.thread.GetStopReason() == lldb.eStopReasonBreakpoint:
85                # we should not stop on breakpoint_2 and _3 because they have false condition
86                self.assertEqual(
87                    self.thread.GetFrameAtIndex(0).GetLineEntry().GetLine(), self.line4
88                )
89                # breakpoint_2 and _3 should not affect step count
90                self.assertGreaterEqual(step_count, steps_expected)
91                break
92
93        # Run the process until termination
94        self.process.Continue()
95        self.assertState(self.process.GetState(), lldb.eStateExited)
96
97    @skipIf(bugnumber="llvm.org/pr31972", hostoslist=["windows"])
98    def test_step_over(self):
99        self.thread.StepOver()
100        # We should be stopped at the breakpoint_2 line with stop plan complete reason
101        self.assertState(self.process.GetState(), lldb.eStateStopped)
102        self.assertStopReason(self.thread.GetStopReason(), lldb.eStopReasonPlanComplete)
103
104        self.thread.StepOver()
105        # We should be stopped at the breakpoint_3 line with stop plan complete reason
106        self.assertState(self.process.GetState(), lldb.eStateStopped)
107        self.assertStopReason(self.thread.GetStopReason(), lldb.eStopReasonPlanComplete)
108
109        self.thread.StepOver()
110        # We should be stopped at the breakpoint_4
111        self.assertState(self.process.GetState(), lldb.eStateStopped)
112        self.assertStopReason(self.thread.GetStopReason(), lldb.eStopReasonBreakpoint)
113        thread1 = lldbutil.get_one_thread_stopped_at_breakpoint(
114            self.process, self.breakpoint4
115        )
116        self.assertEqual(self.thread, thread1, "Didn't stop at breakpoint 4.")
117
118        # Check that stepping does not affect breakpoint's hit count
119        self.assertEqual(self.breakpoint1.GetHitCount(), 1)
120        self.assertEqual(self.breakpoint2.GetHitCount(), 0)
121        self.assertEqual(self.breakpoint3.GetHitCount(), 0)
122        self.assertEqual(self.breakpoint4.GetHitCount(), 1)
123
124        # Run the process until termination
125        self.process.Continue()
126        self.assertState(self.process.GetState(), lldb.eStateExited)
127