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=["aarch64"], oslist=["freebsd", "linux"],
54                        bugnumber="llvm.org/pr44057")
55    def test_step_in_with_python(self):
56        """Test stepping in using avoid-no-debug with dwarf."""
57        self.build()
58        self.get_to_starting_point()
59        self.do_step_in_past_nodebug()
60
61    def setUp(self):
62        TestBase.setUp(self)
63        self.main_source = "with-debug.c"
64        self.main_source_spec = lldb.SBFileSpec("with-debug.c")
65        self.dbg.HandleCommand(
66            "settings set target.process.thread.step-out-avoid-nodebug true")
67
68    def tearDown(self):
69        self.dbg.HandleCommand(
70            "settings set target.process.thread.step-out-avoid-nodebug false")
71        TestBase.tearDown(self)
72
73    def hit_correct_line(self, pattern):
74        target_line = line_number(self.main_source, pattern)
75        self.assertTrue(
76            target_line != 0,
77            "Could not find source pattern " +
78            pattern)
79        cur_line = self.thread.frames[0].GetLineEntry().GetLine()
80        self.assertEqual(
81            cur_line, target_line,
82            "Stepped to line %d instead of expected %d with pattern '%s'." %
83            (cur_line,
84             target_line,
85             pattern))
86
87    def hit_correct_function(self, pattern):
88        name = self.thread.frames[0].GetFunctionName()
89        self.assertTrue(
90            pattern in name, "Got to '%s' not the expected function '%s'." %
91            (name, pattern))
92
93    def get_to_starting_point(self):
94        exe = self.getBuildArtifact("a.out")
95        error = lldb.SBError()
96
97        self.target = self.dbg.CreateTarget(exe)
98        self.assertTrue(self.target, VALID_TARGET)
99
100        inner_bkpt = self.target.BreakpointCreateBySourceRegex(
101            "Stop here and step out of me", self.main_source_spec)
102        self.assertTrue(inner_bkpt, VALID_BREAKPOINT)
103
104        # Now launch the process, and do not stop at entry point.
105        self.process = self.target.LaunchSimple(
106            None, None, self.get_process_working_directory())
107
108        self.assertTrue(self.process, PROCESS_IS_VALID)
109
110        # Now finish, and make sure the return value is correct.
111        threads = lldbutil.get_threads_stopped_at_breakpoint(
112            self.process, inner_bkpt)
113        self.assertEquals(len(threads), 1, "Stopped at inner breakpoint.")
114        self.thread = threads[0]
115
116    def do_step_out_past_nodebug(self):
117        # The first step out takes us to the called_from_nodebug frame, just to make sure setting
118        # step-out-avoid-nodebug doesn't change the behavior in frames with
119        # debug info.
120        self.thread.StepOut()
121        self.hit_correct_line(
122            "intermediate_return_value = called_from_nodebug_actual(some_value)")
123        self.thread.StepOut()
124        self.hit_correct_line(
125            "int return_value = no_debug_caller(5, called_from_nodebug)")
126
127    def do_step_over_past_nodebug(self):
128        self.thread.StepOver()
129        self.hit_correct_line(
130            "intermediate_return_value = called_from_nodebug_actual(some_value)")
131        self.thread.StepOver()
132        self.hit_correct_line("return intermediate_return_value")
133        self.thread.StepOver()
134        # Note, lldb doesn't follow gdb's distinction between "step-out" and "step-over/step-in"
135        # when exiting a frame.  In all cases we leave the pc at the point where we exited the
136        # frame.  In gdb, step-over/step-in move to the end of the line they stepped out to.
137        # If we ever change this we will need to fix this test.
138        self.hit_correct_line(
139            "int return_value = no_debug_caller(5, called_from_nodebug)")
140
141    def do_step_in_past_nodebug(self):
142        self.thread.StepInto()
143        self.hit_correct_line(
144            "intermediate_return_value = called_from_nodebug_actual(some_value)")
145        self.thread.StepInto()
146        self.hit_correct_line("return intermediate_return_value")
147        self.thread.StepInto()
148        # Note, lldb doesn't follow gdb's distinction between "step-out" and "step-over/step-in"
149        # when exiting a frame.  In all cases we leave the pc at the point where we exited the
150        # frame.  In gdb, step-over/step-in move to the end of the line they stepped out to.
151        # If we ever change this we will need to fix this test.
152        self.hit_correct_line(
153            "int return_value = no_debug_caller(5, called_from_nodebug)")
154