1"""
2Test thread step-in, step-over and step-out work with the "Avoid no debug" option.
3"""
4
5
6
7
8import lldb
9from lldbsuite.test.decorators import *
10from lldbsuite.test.lldbtest import *
11from lldbsuite.test import lldbutil
12
13
14class StepAvoidsNoDebugTestCase(TestBase):
15
16    mydir = TestBase.compute_mydir(__file__)
17
18    @add_test_categories(['pyapi'])
19    def test_step_out_with_python(self):
20        """Test stepping out using avoid-no-debug with dsyms."""
21        self.build()
22        self.get_to_starting_point()
23        self.do_step_out_past_nodebug()
24
25    @add_test_categories(['pyapi'])
26    @decorators.expectedFailureAll(
27        compiler="gcc", bugnumber="llvm.org/pr28549")
28    @decorators.expectedFailureAll(
29        compiler="clang",
30        compiler_version=[
31            ">=",
32            "3.9"],
33        archs=["i386"],
34        oslist=no_match(["freebsd"]),
35        bugnumber="llvm.org/pr28549")
36    def test_step_over_with_python(self):
37        """Test stepping over using avoid-no-debug with dwarf."""
38        self.build()
39        self.get_to_starting_point()
40        self.do_step_over_past_nodebug()
41
42    @add_test_categories(['pyapi'])
43    @decorators.expectedFailureAll(
44        compiler="gcc", bugnumber="llvm.org/pr28549")
45    @decorators.expectedFailureAll(
46        compiler="clang",
47        compiler_version=[
48            ">=",
49            "3.9"],
50        archs=["i386"],
51        oslist=no_match(["freebsd"]),
52        bugnumber="llvm.org/pr28549")
53    @expectedFailureAll(archs=["arm64"], bugnumber="<rdar://problem/34026777>")  # lldb doesn't step past last source line in function on arm64
54    @expectedFailureAll(archs=["aarch64"], oslist=["freebsd", "linux"],
55                        bugnumber="llvm.org/pr44057")
56    def test_step_in_with_python(self):
57        """Test stepping in using avoid-no-debug with dwarf."""
58        self.build()
59        self.get_to_starting_point()
60        self.do_step_in_past_nodebug()
61
62    def setUp(self):
63        TestBase.setUp(self)
64        self.main_source = "with-debug.c"
65        self.main_source_spec = lldb.SBFileSpec("with-debug.c")
66        self.dbg.HandleCommand(
67            "settings set target.process.thread.step-out-avoid-nodebug true")
68
69    def tearDown(self):
70        self.dbg.HandleCommand(
71            "settings set target.process.thread.step-out-avoid-nodebug false")
72        TestBase.tearDown(self)
73
74    def hit_correct_line(self, pattern):
75        target_line = line_number(self.main_source, pattern)
76        self.assertTrue(
77            target_line != 0,
78            "Could not find source pattern " +
79            pattern)
80        cur_line = self.thread.frames[0].GetLineEntry().GetLine()
81        self.assertEqual(
82            cur_line, target_line,
83            "Stepped to line %d instead of expected %d with pattern '%s'." %
84            (cur_line,
85             target_line,
86             pattern))
87
88    def hit_correct_function(self, pattern):
89        name = self.thread.frames[0].GetFunctionName()
90        self.assertTrue(
91            pattern in name, "Got to '%s' not the expected function '%s'." %
92            (name, pattern))
93
94    def get_to_starting_point(self):
95        exe = self.getBuildArtifact("a.out")
96        error = lldb.SBError()
97
98        self.target = self.dbg.CreateTarget(exe)
99        self.assertTrue(self.target, VALID_TARGET)
100
101        inner_bkpt = self.target.BreakpointCreateBySourceRegex(
102            "Stop here and step out of me", self.main_source_spec)
103        self.assertTrue(inner_bkpt, VALID_BREAKPOINT)
104
105        # Now launch the process, and do not stop at entry point.
106        self.process = self.target.LaunchSimple(
107            None, None, self.get_process_working_directory())
108
109        self.assertTrue(self.process, PROCESS_IS_VALID)
110
111        # Now finish, and make sure the return value is correct.
112        threads = lldbutil.get_threads_stopped_at_breakpoint(
113            self.process, inner_bkpt)
114        self.assertEquals(len(threads), 1, "Stopped at inner breakpoint.")
115        self.thread = threads[0]
116
117    def do_step_out_past_nodebug(self):
118        # The first step out takes us to the called_from_nodebug frame, just to make sure setting
119        # step-out-avoid-nodebug doesn't change the behavior in frames with
120        # debug info.
121        self.thread.StepOut()
122        self.hit_correct_line(
123            "intermediate_return_value = called_from_nodebug_actual(some_value)")
124        self.thread.StepOut()
125        self.hit_correct_line(
126            "int return_value = no_debug_caller(5, called_from_nodebug)")
127
128    def do_step_over_past_nodebug(self):
129        self.thread.StepOver()
130        self.hit_correct_line(
131            "intermediate_return_value = called_from_nodebug_actual(some_value)")
132        self.thread.StepOver()
133        self.hit_correct_line("return intermediate_return_value")
134        self.thread.StepOver()
135        # Note, lldb doesn't follow gdb's distinction between "step-out" and "step-over/step-in"
136        # when exiting a frame.  In all cases we leave the pc at the point where we exited the
137        # frame.  In gdb, step-over/step-in move to the end of the line they stepped out to.
138        # If we ever change this we will need to fix this test.
139        self.hit_correct_line(
140            "int return_value = no_debug_caller(5, called_from_nodebug)")
141
142    def do_step_in_past_nodebug(self):
143        self.thread.StepInto()
144        self.hit_correct_line(
145            "intermediate_return_value = called_from_nodebug_actual(some_value)")
146        self.thread.StepInto()
147        self.hit_correct_line("return intermediate_return_value")
148        self.thread.StepInto()
149        # Note, lldb doesn't follow gdb's distinction between "step-out" and "step-over/step-in"
150        # when exiting a frame.  In all cases we leave the pc at the point where we exited the
151        # frame.  In gdb, step-over/step-in move to the end of the line they stepped out to.
152        # If we ever change this we will need to fix this test.
153        self.hit_correct_line(
154            "int return_value = no_debug_caller(5, called_from_nodebug)")
155