1"""Test stepping over vrs. hitting breakpoints & subsequent stepping in various forms."""
2
3
4
5import lldb
6from lldbsuite.test.decorators import *
7from lldbsuite.test.lldbtest import *
8from lldbsuite.test import lldbutil
9
10
11class TestCStepping(TestBase):
12
13    mydir = TestBase.compute_mydir(__file__)
14
15    def setUp(self):
16        # Call super's setUp().
17        TestBase.setUp(self)
18        # Find the line numbers that we will step to in main:
19        self.main_source = "main.c"
20
21    @add_test_categories(['pyapi', 'basic_process'])
22    @expectedFailureAll(oslist=['freebsd'], bugnumber='llvm.org/pr17932')
23    @expectedFailureAll(oslist=["linux"], archs=no_match(["i386", "x86_64"]))
24    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24777")
25    @expectedFailureNetBSD
26    def test_and_python_api(self):
27        """Test stepping over vrs. hitting breakpoints & subsequent stepping in various forms."""
28        self.build()
29        exe = self.getBuildArtifact("a.out")
30
31        target = self.dbg.CreateTarget(exe)
32        self.assertTrue(target, VALID_TARGET)
33
34        self.main_source_spec = lldb.SBFileSpec(self.main_source)
35
36        breakpoints_to_disable = []
37
38        break_1_in_main = target.BreakpointCreateBySourceRegex(
39            '// frame select 2, thread step-out while stopped at .c.1..',
40            self.main_source_spec)
41        self.assertTrue(break_1_in_main, VALID_BREAKPOINT)
42        breakpoints_to_disable.append(break_1_in_main)
43
44        break_in_a = target.BreakpointCreateBySourceRegex(
45            '// break here to stop in a before calling b', self.main_source_spec)
46        self.assertTrue(break_in_a, VALID_BREAKPOINT)
47        breakpoints_to_disable.append(break_in_a)
48
49        break_in_b = target.BreakpointCreateBySourceRegex(
50            '// thread step-out while stopped at .c.2..', self.main_source_spec)
51        self.assertTrue(break_in_b, VALID_BREAKPOINT)
52        breakpoints_to_disable.append(break_in_b)
53
54        break_in_c = target.BreakpointCreateBySourceRegex(
55            '// Find the line number of function .c. here.', self.main_source_spec)
56        self.assertTrue(break_in_c, VALID_BREAKPOINT)
57        breakpoints_to_disable.append(break_in_c)
58
59        # Now launch the process, and do not stop at entry point.
60        process = target.LaunchSimple(
61            None, None, self.get_process_working_directory())
62
63        self.assertTrue(process, PROCESS_IS_VALID)
64
65        # The stop reason of the thread should be breakpoint.
66        threads = lldbutil.get_threads_stopped_at_breakpoint(
67            process, break_1_in_main)
68
69        if len(threads) != 1:
70            self.fail("Failed to stop at first breakpoint in main.")
71
72        thread = threads[0]
73
74        # Get the stop id and for fun make sure it increases:
75        old_stop_id = process.GetStopID()
76
77        # Now step over, which should cause us to hit the breakpoint in "a"
78        thread.StepOver()
79
80        # The stop reason of the thread should be breakpoint.
81        threads = lldbutil.get_threads_stopped_at_breakpoint(
82            process, break_in_a)
83        if len(threads) != 1:
84            self.fail("Failed to stop at breakpoint in a.")
85
86        # Check that the stop ID increases:
87        new_stop_id = process.GetStopID()
88        self.assertTrue(
89            new_stop_id > old_stop_id,
90            "Stop ID increases monotonically.")
91
92        thread = threads[0]
93
94        # Step over, and we should hit the breakpoint in b:
95        thread.StepOver()
96
97        threads = lldbutil.get_threads_stopped_at_breakpoint(
98            process, break_in_b)
99        if len(threads) != 1:
100            self.fail("Failed to stop at breakpoint in b.")
101        thread = threads[0]
102
103        # Now try running some function, and make sure that we still end up in the same place
104        # and with the same stop reason.
105        frame = thread.GetFrameAtIndex(0)
106        current_line = frame.GetLineEntry().GetLine()
107        current_file = frame.GetLineEntry().GetFileSpec()
108        current_bp = []
109        current_bp.append(thread.GetStopReasonDataAtIndex(0))
110        current_bp.append(thread.GetStopReasonDataAtIndex(1))
111
112        stop_id_before_expression = process.GetStopID()
113        stop_id_before_including_expressions = process.GetStopID(True)
114
115        frame.EvaluateExpression("(int) printf (print_string)")
116
117        frame = thread.GetFrameAtIndex(0)
118        self.assertEqual(
119            current_line, frame.GetLineEntry().GetLine(),
120            "The line stayed the same after expression.")
121        self.assertEqual(
122            current_file, frame.GetLineEntry().GetFileSpec(),
123            "The file stayed the same after expression.")
124        self.assertEqual(
125            thread.GetStopReason(), lldb.eStopReasonBreakpoint,
126            "We still say we stopped for a breakpoint.")
127        self.assertTrue(thread.GetStopReasonDataAtIndex(0) == current_bp[
128                        0] and thread.GetStopReasonDataAtIndex(1) == current_bp[1], "And it is the same breakpoint.")
129
130        # Also make sure running the expression didn't change the public stop id
131        # but did change if we are asking for expression stops as well.
132        stop_id_after_expression = process.GetStopID()
133        stop_id_after_including_expressions = process.GetStopID(True)
134
135        self.assertEqual(
136            stop_id_before_expression, stop_id_after_expression,
137            "Expression calling doesn't change stop ID")
138
139        self.assertTrue(
140            stop_id_after_including_expressions > stop_id_before_including_expressions,
141            "Stop ID including expressions increments over expression call.")
142
143        # Do the same thing with an expression that's going to crash, and make
144        # sure we are still unchanged.
145
146        frame.EvaluateExpression("((char *) 0)[0] = 'a'")
147
148        frame = thread.GetFrameAtIndex(0)
149        self.assertEqual(
150            current_line, frame.GetLineEntry().GetLine(),
151            "The line stayed the same after expression.")
152        self.assertEqual(
153            current_file, frame.GetLineEntry().GetFileSpec(),
154            "The file stayed the same after expression.")
155        self.assertEqual(
156            thread.GetStopReason(), lldb.eStopReasonBreakpoint,
157            "We still say we stopped for a breakpoint.")
158        self.assertTrue(thread.GetStopReasonDataAtIndex(0) == current_bp[
159                        0] and thread.GetStopReasonDataAtIndex(1) == current_bp[1], "And it is the same breakpoint.")
160
161        # Now continue and make sure we just complete the step:
162        # Disable all our breakpoints first - sometimes the compiler puts two line table entries in for the
163        # breakpoint a "b" and we don't want to hit that.
164        for bkpt in breakpoints_to_disable:
165            bkpt.SetEnabled(False)
166
167        process.Continue()
168
169        self.assertEqual(thread.GetFrameAtIndex(0).GetFunctionName(), "a")
170        self.assertEqual(thread.GetStopReason(), lldb.eStopReasonPlanComplete)
171
172        # And one more time should get us back to main:
173        process.Continue()
174
175        self.assertEqual(thread.GetFrameAtIndex(0).GetFunctionName(), "main")
176        self.assertEqual(thread.GetStopReason(), lldb.eStopReasonPlanComplete)
177
178        # Now make sure we can call a function, break in the called function,
179        # then have "continue" get us back out again:
180        frame = thread.GetFrameAtIndex(0)
181        frame = thread.GetFrameAtIndex(0)
182        current_line = frame.GetLineEntry().GetLine()
183        current_file = frame.GetLineEntry().GetFileSpec()
184
185        break_in_b.SetEnabled(True)
186        options = lldb.SBExpressionOptions()
187        options.SetIgnoreBreakpoints(False)
188        options.SetFetchDynamicValue(False)
189        options.SetUnwindOnError(False)
190        frame.EvaluateExpression("b (4)", options)
191
192        threads = lldbutil.get_threads_stopped_at_breakpoint(
193            process, break_in_b)
194
195        if len(threads) != 1:
196            self.fail("Failed to stop at breakpoint in b when calling b.")
197        thread = threads[0]
198
199        # So do a step over here to make sure we can still do that:
200
201        thread.StepOver()
202
203        # See that we are still in b:
204        func_name = thread.GetFrameAtIndex(0).GetFunctionName()
205        self.assertEqual(
206            func_name, "b",
207            "Should be in 'b', were in %s" %
208            (func_name))
209
210        # Okay, now if we continue, we will finish off our function call and we
211        # should end up back in "a" as if nothing had happened:
212        process.Continue()
213
214        self.assertTrue(thread.GetFrameAtIndex(
215            0).GetLineEntry().GetLine() == current_line)
216        self.assertTrue(thread.GetFrameAtIndex(
217            0).GetLineEntry().GetFileSpec() == current_file)
218
219        # Now we are going to test step in targeting a function:
220
221        break_in_b.SetEnabled(False)
222
223        break_before_complex_1 = target.BreakpointCreateBySourceRegex(
224            '// Stop here to try step in targeting b.', self.main_source_spec)
225        self.assertTrue(break_before_complex_1, VALID_BREAKPOINT)
226
227        break_before_complex_2 = target.BreakpointCreateBySourceRegex(
228            '// Stop here to try step in targeting complex.', self.main_source_spec)
229        self.assertTrue(break_before_complex_2, VALID_BREAKPOINT)
230
231        break_before_complex_3 = target.BreakpointCreateBySourceRegex(
232            '// Stop here to step targeting b and hitting breakpoint.', self.main_source_spec)
233        self.assertTrue(break_before_complex_3, VALID_BREAKPOINT)
234
235        break_before_complex_4 = target.BreakpointCreateBySourceRegex(
236            '// Stop here to make sure bogus target steps over.', self.main_source_spec)
237        self.assertTrue(break_before_complex_4, VALID_BREAKPOINT)
238
239        threads = lldbutil.continue_to_breakpoint(
240            process, break_before_complex_1)
241        self.assertEqual(len(threads), 1)
242        thread = threads[0]
243        break_before_complex_1.SetEnabled(False)
244
245        thread.StepInto("b")
246        self.assertEqual(thread.GetFrameAtIndex(0).GetFunctionName(), "b")
247
248        # Now continue out and stop at the next call to complex.  This time
249        # step all the way into complex:
250        threads = lldbutil.continue_to_breakpoint(
251            process, break_before_complex_2)
252        self.assertEqual(len(threads), 1)
253        thread = threads[0]
254        break_before_complex_2.SetEnabled(False)
255
256        thread.StepInto("complex")
257        self.assertTrue(thread.GetFrameAtIndex(
258            0).GetFunctionName() == "complex")
259
260        # Now continue out and stop at the next call to complex.  This time
261        # enable breakpoints in a and c and then step targeting b:
262        threads = lldbutil.continue_to_breakpoint(
263            process, break_before_complex_3)
264        self.assertEqual(len(threads), 1)
265        thread = threads[0]
266        break_before_complex_3.SetEnabled(False)
267
268        break_at_start_of_a = target.BreakpointCreateByName('a')
269        break_at_start_of_c = target.BreakpointCreateByName('c')
270
271        thread.StepInto("b")
272        threads = lldbutil.get_stopped_threads(
273            process, lldb.eStopReasonBreakpoint)
274
275        self.assertEqual(len(threads), 1)
276        thread = threads[0]
277        stop_break_id = thread.GetStopReasonDataAtIndex(0)
278        self.assertTrue(stop_break_id == break_at_start_of_a.GetID()
279                        or stop_break_id == break_at_start_of_c.GetID())
280
281        break_at_start_of_a.SetEnabled(False)
282        break_at_start_of_c.SetEnabled(False)
283
284        process.Continue()
285        self.assertEqual(thread.GetFrameAtIndex(0).GetFunctionName(), "b")
286
287        # Now continue out and stop at the next call to complex.  This time
288        # enable breakpoints in a and c and then step targeting b:
289        threads = lldbutil.continue_to_breakpoint(
290            process, break_before_complex_4)
291        self.assertEqual(len(threads), 1)
292        thread = threads[0]
293        break_before_complex_4.SetEnabled(False)
294
295        thread.StepInto("NoSuchFunction")
296        self.assertEqual(thread.GetFrameAtIndex(0).GetFunctionName(), "main")
297