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