199451b44SJordan Rupprecht"""Test stepping over and into inlined functions."""
299451b44SJordan Rupprecht
399451b44SJordan Rupprecht
499451b44SJordan Rupprecht
599451b44SJordan Rupprechtimport lldb
699451b44SJordan Rupprechtfrom lldbsuite.test.decorators import *
799451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import *
899451b44SJordan Rupprechtfrom lldbsuite.test import lldbutil
999451b44SJordan Rupprecht
1099451b44SJordan Rupprecht
1199451b44SJordan Rupprechtclass TestInlineStepping(TestBase):
1299451b44SJordan Rupprecht
1399451b44SJordan Rupprecht    @add_test_categories(['pyapi'])
1499451b44SJordan Rupprecht    @expectedFailureAll(
1599451b44SJordan Rupprecht        compiler="icc",
1699451b44SJordan Rupprecht        bugnumber="# Not really a bug.  ICC combines two inlined functions.")
1799451b44SJordan Rupprecht    def test_with_python_api(self):
1899451b44SJordan Rupprecht        """Test stepping over and into inlined functions."""
1999451b44SJordan Rupprecht        self.build()
2099451b44SJordan Rupprecht        self.inline_stepping()
2199451b44SJordan Rupprecht
2299451b44SJordan Rupprecht    @add_test_categories(['pyapi'])
2399451b44SJordan Rupprecht    def test_step_over_with_python_api(self):
2499451b44SJordan Rupprecht        """Test stepping over and into inlined functions."""
2599451b44SJordan Rupprecht        self.build()
2699451b44SJordan Rupprecht        self.inline_stepping_step_over()
2799451b44SJordan Rupprecht
2899451b44SJordan Rupprecht    @add_test_categories(['pyapi'])
2999451b44SJordan Rupprecht    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr32343")
3099451b44SJordan Rupprecht    def test_step_in_template_with_python_api(self):
3199451b44SJordan Rupprecht        """Test stepping in to templated functions."""
3299451b44SJordan Rupprecht        self.build()
3399451b44SJordan Rupprecht        self.step_in_template()
3499451b44SJordan Rupprecht
3599451b44SJordan Rupprecht    def setUp(self):
3699451b44SJordan Rupprecht        # Call super's setUp().
3799451b44SJordan Rupprecht        TestBase.setUp(self)
3899451b44SJordan Rupprecht        # Find the line numbers that we will step to in main:
3999451b44SJordan Rupprecht        self.main_source = "calling.cpp"
4099451b44SJordan Rupprecht        self.source_lines = {}
4199451b44SJordan Rupprecht        functions = [
4299451b44SJordan Rupprecht            'caller_ref_1',
4399451b44SJordan Rupprecht            'caller_ref_2',
4499451b44SJordan Rupprecht            'inline_ref_1',
4599451b44SJordan Rupprecht            'inline_ref_2',
4699451b44SJordan Rupprecht            'called_by_inline_ref',
4799451b44SJordan Rupprecht            'caller_trivial_1',
4899451b44SJordan Rupprecht            'caller_trivial_2',
4999451b44SJordan Rupprecht            'inline_trivial_1',
5099451b44SJordan Rupprecht            'inline_trivial_2',
5199451b44SJordan Rupprecht            'called_by_inline_trivial']
5299451b44SJordan Rupprecht        for name in functions:
5399451b44SJordan Rupprecht            self.source_lines[name] = line_number(
5499451b44SJordan Rupprecht                self.main_source, "// In " + name + ".")
5599451b44SJordan Rupprecht        self.main_source_spec = lldb.SBFileSpec(self.main_source)
5699451b44SJordan Rupprecht
5799451b44SJordan Rupprecht    def do_step(self, step_type, destination_line_entry, test_stack_depth):
5899451b44SJordan Rupprecht        expected_stack_depth = self.thread.GetNumFrames()
5999451b44SJordan Rupprecht        if step_type == "into":
6099451b44SJordan Rupprecht            expected_stack_depth += 1
6199451b44SJordan Rupprecht            self.thread.StepInto()
6299451b44SJordan Rupprecht        elif step_type == "out":
6399451b44SJordan Rupprecht            expected_stack_depth -= 1
6499451b44SJordan Rupprecht            self.thread.StepOut()
6599451b44SJordan Rupprecht        elif step_type == "over":
6699451b44SJordan Rupprecht            self.thread.StepOver()
6799451b44SJordan Rupprecht        else:
6899451b44SJordan Rupprecht            self.fail("Unrecognized step type: " + step_type)
6999451b44SJordan Rupprecht
7099451b44SJordan Rupprecht        threads = lldbutil.get_stopped_threads(
7199451b44SJordan Rupprecht            self.process, lldb.eStopReasonPlanComplete)
7299451b44SJordan Rupprecht        if len(threads) != 1:
7399451b44SJordan Rupprecht            destination_description = lldb.SBStream()
7499451b44SJordan Rupprecht            destination_line_entry.GetDescription(destination_description)
7599451b44SJordan Rupprecht            self.fail(
7699451b44SJordan Rupprecht                "Failed to stop due to step " +
7799451b44SJordan Rupprecht                step_type +
7899451b44SJordan Rupprecht                " operation stepping to: " +
7999451b44SJordan Rupprecht                destination_description.GetData())
8099451b44SJordan Rupprecht
8199451b44SJordan Rupprecht        self.thread = threads[0]
8299451b44SJordan Rupprecht
8399451b44SJordan Rupprecht        stop_line_entry = self.thread.GetFrameAtIndex(0).GetLineEntry()
8499451b44SJordan Rupprecht        self.assertTrue(
8599451b44SJordan Rupprecht            stop_line_entry.IsValid(),
8699451b44SJordan Rupprecht            "Stop line entry was not valid.")
8799451b44SJordan Rupprecht
8899451b44SJordan Rupprecht        # Don't use the line entry equal operator because we don't care about
8999451b44SJordan Rupprecht        # the column number.
9099451b44SJordan Rupprecht        stop_at_right_place = (stop_line_entry.GetFileSpec() == destination_line_entry.GetFileSpec(
9199451b44SJordan Rupprecht        ) and stop_line_entry.GetLine() == destination_line_entry.GetLine())
9299451b44SJordan Rupprecht        if not stop_at_right_place:
9399451b44SJordan Rupprecht            destination_description = lldb.SBStream()
9499451b44SJordan Rupprecht            destination_line_entry.GetDescription(destination_description)
9599451b44SJordan Rupprecht
9699451b44SJordan Rupprecht            actual_description = lldb.SBStream()
9799451b44SJordan Rupprecht            stop_line_entry.GetDescription(actual_description)
9899451b44SJordan Rupprecht
9999451b44SJordan Rupprecht            self.fail(
10099451b44SJordan Rupprecht                "Step " +
10199451b44SJordan Rupprecht                step_type +
10299451b44SJordan Rupprecht                " stopped at wrong place: expected: " +
10399451b44SJordan Rupprecht                destination_description.GetData() +
10499451b44SJordan Rupprecht                " got: " +
10599451b44SJordan Rupprecht                actual_description.GetData() +
10699451b44SJordan Rupprecht                ".")
10799451b44SJordan Rupprecht
10899451b44SJordan Rupprecht        real_stack_depth = self.thread.GetNumFrames()
10999451b44SJordan Rupprecht
11099451b44SJordan Rupprecht        if test_stack_depth and real_stack_depth != expected_stack_depth:
11199451b44SJordan Rupprecht            destination_description = lldb.SBStream()
11299451b44SJordan Rupprecht            destination_line_entry.GetDescription(destination_description)
11399451b44SJordan Rupprecht            self.fail(
11499451b44SJordan Rupprecht                "Step %s to %s got wrong number of frames, should be: %d was: %d." %
11599451b44SJordan Rupprecht                (step_type,
11699451b44SJordan Rupprecht                 destination_description.GetData(),
11799451b44SJordan Rupprecht                 expected_stack_depth,
11899451b44SJordan Rupprecht                 real_stack_depth))
11999451b44SJordan Rupprecht
12099451b44SJordan Rupprecht    def run_step_sequence(self, step_sequence):
12199451b44SJordan Rupprecht        """This function takes a list of duples instructing how to run the program.  The first element in each duple is
12299451b44SJordan Rupprecht           a source pattern for the target location, and the second is the operation that will take you from the current
12399451b44SJordan Rupprecht           source location to the target location.  It will then run all the steps in the sequence.
12499451b44SJordan Rupprecht           It will check that you arrived at the expected source location at each step, and that the stack depth changed
12599451b44SJordan Rupprecht           correctly for the operation in the sequence."""
12699451b44SJordan Rupprecht
12799451b44SJordan Rupprecht        target_line_entry = lldb.SBLineEntry()
12899451b44SJordan Rupprecht        target_line_entry.SetFileSpec(self.main_source_spec)
12999451b44SJordan Rupprecht
13099451b44SJordan Rupprecht        test_stack_depth = True
13199451b44SJordan Rupprecht        # Work around for <rdar://problem/16363195>, the darwin unwinder seems flakey about whether it duplicates the first frame
13299451b44SJordan Rupprecht        # or not, which makes counting stack depth unreliable.
13399451b44SJordan Rupprecht        if self.platformIsDarwin():
13499451b44SJordan Rupprecht            test_stack_depth = False
13599451b44SJordan Rupprecht
13699451b44SJordan Rupprecht        for step_pattern in step_sequence:
13799451b44SJordan Rupprecht            step_stop_line = line_number(self.main_source, step_pattern[0])
13899451b44SJordan Rupprecht            target_line_entry.SetLine(step_stop_line)
13999451b44SJordan Rupprecht            self.do_step(step_pattern[1], target_line_entry, test_stack_depth)
14099451b44SJordan Rupprecht
14199451b44SJordan Rupprecht    def inline_stepping(self):
14299451b44SJordan Rupprecht        """Use Python APIs to test stepping over and hitting breakpoints."""
14399451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
14499451b44SJordan Rupprecht
14599451b44SJordan Rupprecht        target = self.dbg.CreateTarget(exe)
14699451b44SJordan Rupprecht        self.assertTrue(target, VALID_TARGET)
14799451b44SJordan Rupprecht
14899451b44SJordan Rupprecht        break_1_in_main = target.BreakpointCreateBySourceRegex(
14999451b44SJordan Rupprecht            '// Stop here and step over to set up stepping over.', self.main_source_spec)
15099451b44SJordan Rupprecht        self.assertTrue(break_1_in_main, VALID_BREAKPOINT)
15199451b44SJordan Rupprecht
15299451b44SJordan Rupprecht        # Now launch the process, and do not stop at entry point.
15399451b44SJordan Rupprecht        self.process = target.LaunchSimple(
15499451b44SJordan Rupprecht            None, None, self.get_process_working_directory())
15599451b44SJordan Rupprecht
15699451b44SJordan Rupprecht        self.assertTrue(self.process, PROCESS_IS_VALID)
15799451b44SJordan Rupprecht
15899451b44SJordan Rupprecht        # The stop reason of the thread should be breakpoint.
15999451b44SJordan Rupprecht        threads = lldbutil.get_threads_stopped_at_breakpoint(
16099451b44SJordan Rupprecht            self.process, break_1_in_main)
16199451b44SJordan Rupprecht
16299451b44SJordan Rupprecht        if len(threads) != 1:
16399451b44SJordan Rupprecht            self.fail("Failed to stop at first breakpoint in main.")
16499451b44SJordan Rupprecht
16599451b44SJordan Rupprecht        self.thread = threads[0]
16699451b44SJordan Rupprecht
16799451b44SJordan Rupprecht        # Step over the inline_value = 0 line to get us to inline_trivial_1 called from main.  Doing it this way works
16899451b44SJordan Rupprecht        # around a bug in lldb where the breakpoint on the containing line of an inlined function with no return value
16999451b44SJordan Rupprecht        # gets set past the insertion line in the function.
17099451b44SJordan Rupprecht        # Then test stepping over a simple inlined function.  Note, to test all the parts of the inlined stepping
17199451b44SJordan Rupprecht        # the calls inline_stepping_1 and inline_stepping_2 should line up at the same address, that way we will test
17299451b44SJordan Rupprecht        # the "virtual" stepping.
17399451b44SJordan Rupprecht        # FIXME: Put in a check to see if that is true and warn if it is not.
17499451b44SJordan Rupprecht
17599451b44SJordan Rupprecht        step_sequence = [["// At inline_trivial_1 called from main.", "over"],
17699451b44SJordan Rupprecht                         ["// At first call of caller_trivial_1 in main.", "over"]]
17799451b44SJordan Rupprecht        self.run_step_sequence(step_sequence)
17899451b44SJordan Rupprecht
17999451b44SJordan Rupprecht        # Now step from caller_ref_1 all the way into called_by_inline_trivial
18099451b44SJordan Rupprecht
18199451b44SJordan Rupprecht        step_sequence = [["// In caller_trivial_1.", "into"],
18299451b44SJordan Rupprecht                         ["// In caller_trivial_2.", "into"],
18399451b44SJordan Rupprecht                         ["// In inline_trivial_1.", "into"],
18499451b44SJordan Rupprecht                         ["// In inline_trivial_2.", "into"],
18599451b44SJordan Rupprecht                         ["// At caller_by_inline_trivial in inline_trivial_2.", "over"],
18699451b44SJordan Rupprecht                         ["// In called_by_inline_trivial.", "into"]]
18799451b44SJordan Rupprecht        self.run_step_sequence(step_sequence)
18899451b44SJordan Rupprecht
18999451b44SJordan Rupprecht        # Now run to the inline_trivial_1 just before the immediate step into
19099451b44SJordan Rupprecht        # inline_trivial_2:
19199451b44SJordan Rupprecht
19299451b44SJordan Rupprecht        break_2_in_main = target.BreakpointCreateBySourceRegex(
19399451b44SJordan Rupprecht            '// At second call of caller_trivial_1 in main.', self.main_source_spec)
19499451b44SJordan Rupprecht        self.assertTrue(break_2_in_main, VALID_BREAKPOINT)
19599451b44SJordan Rupprecht
19699451b44SJordan Rupprecht        threads = lldbutil.continue_to_breakpoint(
19799451b44SJordan Rupprecht            self.process, break_2_in_main)
198*0ed758b2SDave Lee        self.assertEqual(
199*0ed758b2SDave Lee            len(threads), 1,
20099451b44SJordan Rupprecht            "Successfully ran to call site of second caller_trivial_1 call.")
20199451b44SJordan Rupprecht        self.thread = threads[0]
20299451b44SJordan Rupprecht
20399451b44SJordan Rupprecht        step_sequence = [["// In caller_trivial_1.", "into"],
20499451b44SJordan Rupprecht                         ["// In caller_trivial_2.", "into"],
20599451b44SJordan Rupprecht                         ["// In inline_trivial_1.", "into"]]
20699451b44SJordan Rupprecht        self.run_step_sequence(step_sequence)
20799451b44SJordan Rupprecht
20899451b44SJordan Rupprecht        # Then call some trivial function, and make sure we end up back where
20999451b44SJordan Rupprecht        # we were in the inlined call stack:
21099451b44SJordan Rupprecht
21199451b44SJordan Rupprecht        frame = self.thread.GetFrameAtIndex(0)
21299451b44SJordan Rupprecht        before_line_entry = frame.GetLineEntry()
21399451b44SJordan Rupprecht        value = frame.EvaluateExpression("function_to_call()")
21499451b44SJordan Rupprecht        after_line_entry = frame.GetLineEntry()
21599451b44SJordan Rupprecht
216*0ed758b2SDave Lee        self.assertEqual(
217*0ed758b2SDave Lee            before_line_entry.GetLine(), after_line_entry.GetLine(),
21899451b44SJordan Rupprecht            "Line entry before and after function calls are the same.")
21999451b44SJordan Rupprecht
22099451b44SJordan Rupprecht        # Now make sure stepping OVER in the middle of the stack works, and
22199451b44SJordan Rupprecht        # then check finish from the inlined frame:
22299451b44SJordan Rupprecht
22399451b44SJordan Rupprecht        step_sequence = [["// At increment in inline_trivial_1.", "over"],
22499451b44SJordan Rupprecht                         ["// At increment in caller_trivial_2.", "out"]]
22599451b44SJordan Rupprecht        self.run_step_sequence(step_sequence)
22699451b44SJordan Rupprecht
22799451b44SJordan Rupprecht        # Now run to the place in main just before the first call to
22899451b44SJordan Rupprecht        # caller_ref_1:
22999451b44SJordan Rupprecht
23099451b44SJordan Rupprecht        break_3_in_main = target.BreakpointCreateBySourceRegex(
23199451b44SJordan Rupprecht            '// At first call of caller_ref_1 in main.', self.main_source_spec)
23299451b44SJordan Rupprecht        self.assertTrue(break_3_in_main, VALID_BREAKPOINT)
23399451b44SJordan Rupprecht
23499451b44SJordan Rupprecht        threads = lldbutil.continue_to_breakpoint(
23599451b44SJordan Rupprecht            self.process, break_3_in_main)
236*0ed758b2SDave Lee        self.assertEqual(
237*0ed758b2SDave Lee            len(threads), 1,
23899451b44SJordan Rupprecht            "Successfully ran to call site of first caller_ref_1 call.")
23999451b44SJordan Rupprecht        self.thread = threads[0]
24099451b44SJordan Rupprecht
24199451b44SJordan Rupprecht        step_sequence = [["// In caller_ref_1.", "into"],
24299451b44SJordan Rupprecht                         ["// In caller_ref_2.", "into"],
24399451b44SJordan Rupprecht                         ["// In inline_ref_1.", "into"],
24499451b44SJordan Rupprecht                         ["// In inline_ref_2.", "into"],
24599451b44SJordan Rupprecht                         ["// In called_by_inline_ref.", "into"],
24699451b44SJordan Rupprecht                         ["// In inline_ref_2.", "out"],
24799451b44SJordan Rupprecht                         ["// In inline_ref_1.", "out"],
24899451b44SJordan Rupprecht                         ["// At increment in inline_ref_1.", "over"],
24999451b44SJordan Rupprecht                         ["// In caller_ref_2.", "out"],
25099451b44SJordan Rupprecht                         ["// At increment in caller_ref_2.", "over"]]
25199451b44SJordan Rupprecht        self.run_step_sequence(step_sequence)
25299451b44SJordan Rupprecht
25399451b44SJordan Rupprecht    def inline_stepping_step_over(self):
25499451b44SJordan Rupprecht        """Use Python APIs to test stepping over and hitting breakpoints."""
25599451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
25699451b44SJordan Rupprecht
25799451b44SJordan Rupprecht        target = self.dbg.CreateTarget(exe)
25899451b44SJordan Rupprecht        self.assertTrue(target, VALID_TARGET)
25999451b44SJordan Rupprecht
26099451b44SJordan Rupprecht        break_1_in_main = target.BreakpointCreateBySourceRegex(
26199451b44SJordan Rupprecht            '// At second call of caller_ref_1 in main.', self.main_source_spec)
26299451b44SJordan Rupprecht        self.assertTrue(break_1_in_main, VALID_BREAKPOINT)
26399451b44SJordan Rupprecht
26499451b44SJordan Rupprecht        # Now launch the process, and do not stop at entry point.
26599451b44SJordan Rupprecht        self.process = target.LaunchSimple(
26699451b44SJordan Rupprecht            None, None, self.get_process_working_directory())
26799451b44SJordan Rupprecht
26899451b44SJordan Rupprecht        self.assertTrue(self.process, PROCESS_IS_VALID)
26999451b44SJordan Rupprecht
27099451b44SJordan Rupprecht        # The stop reason of the thread should be breakpoint.
27199451b44SJordan Rupprecht        threads = lldbutil.get_threads_stopped_at_breakpoint(
27299451b44SJordan Rupprecht            self.process, break_1_in_main)
27399451b44SJordan Rupprecht
27499451b44SJordan Rupprecht        if len(threads) != 1:
27599451b44SJordan Rupprecht            self.fail("Failed to stop at first breakpoint in main.")
27699451b44SJordan Rupprecht
27799451b44SJordan Rupprecht        self.thread = threads[0]
27899451b44SJordan Rupprecht
27999451b44SJordan Rupprecht        step_sequence = [["// In caller_ref_1.", "into"],
28099451b44SJordan Rupprecht                         ["// In caller_ref_2.", "into"],
28199451b44SJordan Rupprecht                         ["// At increment in caller_ref_2.", "over"]]
28299451b44SJordan Rupprecht        self.run_step_sequence(step_sequence)
28399451b44SJordan Rupprecht
28499451b44SJordan Rupprecht    def step_in_template(self):
28599451b44SJordan Rupprecht        """Use Python APIs to test stepping in to templated functions."""
28699451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
28799451b44SJordan Rupprecht
28899451b44SJordan Rupprecht        target = self.dbg.CreateTarget(exe)
28999451b44SJordan Rupprecht        self.assertTrue(target, VALID_TARGET)
29099451b44SJordan Rupprecht
29199451b44SJordan Rupprecht        break_1_in_main = target.BreakpointCreateBySourceRegex(
29299451b44SJordan Rupprecht            '// Call max_value template', self.main_source_spec)
29399451b44SJordan Rupprecht        self.assertTrue(break_1_in_main, VALID_BREAKPOINT)
29499451b44SJordan Rupprecht
29599451b44SJordan Rupprecht        break_2_in_main = target.BreakpointCreateBySourceRegex(
29699451b44SJordan Rupprecht            '// Call max_value specialized', self.main_source_spec)
29799451b44SJordan Rupprecht        self.assertTrue(break_2_in_main, VALID_BREAKPOINT)
29899451b44SJordan Rupprecht
29999451b44SJordan Rupprecht        # Now launch the process, and do not stop at entry point.
30099451b44SJordan Rupprecht        self.process = target.LaunchSimple(
30199451b44SJordan Rupprecht            None, None, self.get_process_working_directory())
30299451b44SJordan Rupprecht        self.assertTrue(self.process, PROCESS_IS_VALID)
30399451b44SJordan Rupprecht
30499451b44SJordan Rupprecht        # The stop reason of the thread should be breakpoint.
30599451b44SJordan Rupprecht        threads = lldbutil.get_threads_stopped_at_breakpoint(
30699451b44SJordan Rupprecht            self.process, break_1_in_main)
30799451b44SJordan Rupprecht
30899451b44SJordan Rupprecht        if len(threads) != 1:
30999451b44SJordan Rupprecht            self.fail("Failed to stop at first breakpoint in main.")
31099451b44SJordan Rupprecht
31199451b44SJordan Rupprecht        self.thread = threads[0]
31299451b44SJordan Rupprecht
31399451b44SJordan Rupprecht        step_sequence = [["// In max_value template", "into"]]
31499451b44SJordan Rupprecht        self.run_step_sequence(step_sequence)
31599451b44SJordan Rupprecht
31699451b44SJordan Rupprecht        threads = lldbutil.continue_to_breakpoint(
31799451b44SJordan Rupprecht            self.process, break_2_in_main)
31899451b44SJordan Rupprecht        self.assertEqual(
31999451b44SJordan Rupprecht            len(threads),
32099451b44SJordan Rupprecht            1,
32199451b44SJordan Rupprecht            "Successfully ran to call site of second caller_trivial_1 call.")
32299451b44SJordan Rupprecht        self.thread = threads[0]
32399451b44SJordan Rupprecht
32499451b44SJordan Rupprecht        step_sequence = [["// In max_value specialized", "into"]]
32599451b44SJordan Rupprecht        self.run_step_sequence(step_sequence)
326