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    @add_test_categories(['pyapi'])
17    @expectedFailureAll(archs=["aarch64"], oslist=["windows"], bugnumber="llvm.org/pr56292")
18    def test_step_out_with_python(self):
19        """Test stepping out using avoid-no-debug with dsyms."""
20        self.build()
21        self.get_to_starting_point()
22        self.do_step_out_past_nodebug()
23
24    @add_test_categories(['pyapi'])
25    @decorators.expectedFailureAll(
26        compiler="gcc", bugnumber="llvm.org/pr28549")
27    @decorators.expectedFailureAll(
28        compiler="clang",
29        compiler_version=[
30            ">=",
31            "3.9"],
32        archs=["i386"],
33        oslist=no_match(["freebsd"]),
34        bugnumber="llvm.org/pr28549")
35    @expectedFailureAll(archs=["aarch64"], oslist=["windows"], bugnumber="llvm.org/pr56292")
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=["windows"], bugnumber="llvm.org/pr56292")
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.assertEqual(
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