1"""
2Test getting return-values correctly when stepping out
3"""
4
5
6
7import lldb
8from lldbsuite.test.decorators import *
9from lldbsuite.test.lldbtest import *
10from lldbsuite.test import lldbutil
11
12
13class ReturnValueTestCase(TestBase):
14
15    def affected_by_pr33042(self):
16        return ("clang" in self.getCompiler() and self.isAArch64() and
17            self.getPlatform() == "linux")
18
19    def affected_by_pr44132(self):
20        return (self.getArchitecture() in ["aarch64", "arm"] and
21                self.getPlatform() in ["freebsd", "linux"])
22
23    # ABIMacOSX_arm64 and the SysV_arm64 don't restore the storage value for memory returns on function
24    # exit, so lldb shouldn't attempt to fetch memory for those return types, as there is
25    # no easy way to guarantee that they will be correct.  This is a list of the memory
26    # return functions defined in the test file:
27    arm_no_return_values = ["return_five_int", "return_one_int_one_double_one_int",
28                            "return_one_short_one_double_one_short", "return_vector_size_float32_32",
29                            "return_ext_vector_size_float32_8"]
30    def should_report_return_value(self, func_name):
31        abi = self.target.GetABIName()
32        if not abi in ["SysV-arm64", "ABIMacOSX_arm64", "macosx-arm"]:
33            return True
34        return not func_name in self.arm_no_return_values
35
36    @expectedFailureAll(oslist=["freebsd"], archs=["i386"],
37                        bugnumber="llvm.org/pr48376")
38    @expectedFailureAll(oslist=["macosx"], archs=["i386"], bugnumber="<rdar://problem/28719652>")
39    @expectedFailureAll(
40        oslist=["linux"],
41        compiler="clang",
42        compiler_version=[
43            "<=",
44            "3.6"],
45        archs=["i386"])
46    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24778")
47    @add_test_categories(['pyapi'])
48    def test_with_python(self):
49        """Test getting return values from stepping out."""
50        self.build()
51        exe = self.getBuildArtifact("a.out")
52        (self.target, self.process, thread, inner_sint_bkpt) = lldbutil.run_to_name_breakpoint(self, "inner_sint", exe_name = exe)
53
54        error = lldb.SBError()
55
56        # inner_sint returns the variable value, so capture that here:
57        in_int = thread.GetFrameAtIndex(0).FindVariable(
58            "value").GetValueAsSigned(error)
59        self.assertSuccess(error)
60
61        thread.StepOut()
62
63        self.assertState(self.process.GetState(), lldb.eStateStopped)
64        self.assertEquals(thread.GetStopReason(), lldb.eStopReasonPlanComplete)
65
66        frame = thread.GetFrameAtIndex(0)
67        fun_name = frame.GetFunctionName()
68        self.assertEquals(fun_name, "outer_sint(int)")
69
70        return_value = thread.GetStopReturnValue()
71        self.assertTrue(return_value.IsValid())
72
73        ret_int = return_value.GetValueAsSigned(error)
74        self.assertSuccess(error)
75        self.assertEquals(in_int, ret_int)
76
77        # Run again and we will stop in inner_sint the second time outer_sint is called.
78        # Then test stepping out two frames at once:
79
80        thread_list = lldbutil.continue_to_breakpoint(self.process, inner_sint_bkpt)
81        self.assertEquals(len(thread_list), 1)
82        thread = thread_list[0]
83
84        # We are done with the inner_sint breakpoint:
85        self.target.BreakpointDelete(inner_sint_bkpt.GetID())
86
87        frame = thread.GetFrameAtIndex(1)
88        fun_name = frame.GetFunctionName()
89        self.assertEquals(fun_name, "outer_sint(int)")
90        in_int = frame.FindVariable("value").GetValueAsSigned(error)
91        self.assertSuccess(error)
92
93        thread.StepOutOfFrame(frame)
94
95        self.assertState(self.process.GetState(), lldb.eStateStopped)
96        self.assertEquals(thread.GetStopReason(), lldb.eStopReasonPlanComplete)
97        frame = thread.GetFrameAtIndex(0)
98        fun_name = frame.GetFunctionName()
99        self.assertEquals(fun_name, "main")
100
101        ret_value = thread.GetStopReturnValue()
102        self.assertTrue(return_value.IsValid())
103        ret_int = ret_value.GetValueAsSigned(error)
104        self.assertSuccess(error)
105        self.assertEquals(2 * in_int, ret_int)
106
107        # Now try some simple returns that have different types:
108        inner_float_bkpt = self.target.BreakpointCreateByName(
109            "inner_float(float)", exe)
110        self.assertTrue(inner_float_bkpt, VALID_BREAKPOINT)
111        self.process.Continue()
112        thread_list = lldbutil.get_threads_stopped_at_breakpoint(
113            self.process, inner_float_bkpt)
114        self.assertEquals(len(thread_list), 1)
115        thread = thread_list[0]
116
117        self.target.BreakpointDelete(inner_float_bkpt.GetID())
118
119        frame = thread.GetFrameAtIndex(0)
120        in_value = frame.FindVariable("value")
121        in_float = float(in_value.GetValue())
122        thread.StepOut()
123
124        self.assertState(self.process.GetState(), lldb.eStateStopped)
125        self.assertEquals(thread.GetStopReason(), lldb.eStopReasonPlanComplete)
126
127        frame = thread.GetFrameAtIndex(0)
128        fun_name = frame.GetFunctionName()
129        self.assertEquals(fun_name, "outer_float(float)")
130
131        #return_value = thread.GetStopReturnValue()
132        #self.assertTrue(return_value.IsValid())
133        #return_float = float(return_value.GetValue())
134
135        #self.assertEqual(in_float, return_float)
136
137        if not self.affected_by_pr44132():
138            self.return_and_test_struct_value("return_one_int")
139            self.return_and_test_struct_value("return_two_int")
140            self.return_and_test_struct_value("return_three_int")
141            self.return_and_test_struct_value("return_four_int")
142            if not self.affected_by_pr33042():
143                self.return_and_test_struct_value("return_five_int")
144            self.return_and_test_struct_value("return_two_double")
145            self.return_and_test_struct_value("return_one_double_two_float")
146            self.return_and_test_struct_value("return_one_int_one_float_one_int")
147
148            self.return_and_test_struct_value("return_one_pointer")
149            self.return_and_test_struct_value("return_two_pointer")
150            self.return_and_test_struct_value("return_one_float_one_pointer")
151            self.return_and_test_struct_value("return_one_int_one_pointer")
152            self.return_and_test_struct_value("return_three_short_one_float")
153
154            self.return_and_test_struct_value("return_one_int_one_double")
155            self.return_and_test_struct_value("return_one_int_one_double_one_int")
156            self.return_and_test_struct_value(
157                "return_one_short_one_double_one_short")
158            self.return_and_test_struct_value("return_one_float_one_int_one_float")
159            self.return_and_test_struct_value("return_two_float")
160            # I am leaving out the packed test until we have a way to tell CLANG
161            # about alignment when reading DWARF for packed types.
162            #self.return_and_test_struct_value ("return_one_int_one_double_packed")
163            self.return_and_test_struct_value("return_one_int_one_long")
164
165    @expectedFailureAll(oslist=["freebsd"], archs=["i386"],
166                        bugnumber="llvm.org/pr48376")
167    @expectedFailureAll(oslist=["macosx"], archs=["i386"], bugnumber="<rdar://problem/28719652>")
168    @expectedFailureAll(
169        oslist=["linux"],
170        compiler="clang",
171        compiler_version=[
172            "<=",
173            "3.6"],
174        archs=["i386"])
175    @expectedFailureAll(compiler=["gcc"], archs=["x86_64", "i386"])
176    @expectedFailureAll(oslist=["windows"], archs=["i[3-6]86", "x86_64"], bugnumber="llvm.org/pr24778")
177    def test_vector_values(self):
178        self.build()
179        exe = self.getBuildArtifact("a.out")
180        error = lldb.SBError()
181
182        self.target = self.dbg.CreateTarget(exe)
183        self.assertTrue(self.target, VALID_TARGET)
184
185        main_bktp = self.target.BreakpointCreateByName("main", exe)
186        self.assertTrue(main_bktp, VALID_BREAKPOINT)
187
188        self.process = self.target.LaunchSimple(
189            None, None, self.get_process_working_directory())
190        self.assertEqual(len(lldbutil.get_threads_stopped_at_breakpoint(
191            self.process, main_bktp)), 1)
192        self.return_and_test_struct_value("return_vector_size_float32_8")
193        self.return_and_test_struct_value("return_vector_size_float32_16")
194        if not self.affected_by_pr44132():
195            self.return_and_test_struct_value("return_vector_size_float32_32")
196        self.return_and_test_struct_value("return_ext_vector_size_float32_2")
197        self.return_and_test_struct_value("return_ext_vector_size_float32_4")
198        if not self.affected_by_pr44132():
199            self.return_and_test_struct_value("return_ext_vector_size_float32_8")
200
201    # limit the nested struct and class tests to only x86_64
202    @skipIf(archs=no_match(['x86_64']))
203    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24778")
204    def test_for_cpp_support(self):
205        self.build()
206        exe = self.getBuildArtifact("a.out")
207        (self.target, self.process, thread, inner_sint_bkpt) = lldbutil.run_to_name_breakpoint(self, "inner_sint", exe_name = exe)
208
209        error = lldb.SBError()
210
211        self.target = self.dbg.CreateTarget(exe)
212        self.assertTrue(self.target, VALID_TARGET)
213
214        main_bktp = self.target.BreakpointCreateByName("main", exe)
215        self.assertTrue(main_bktp, VALID_BREAKPOINT)
216
217        self.process = self.target.LaunchSimple(
218            None, None, self.get_process_working_directory())
219        self.assertEqual(len(lldbutil.get_threads_stopped_at_breakpoint(
220            self.process, main_bktp)), 1)
221        # nested struct tests
222        self.return_and_test_struct_value("return_nested_one_float_three_base")
223        self.return_and_test_struct_value("return_double_nested_one_float_one_nested")
224        self.return_and_test_struct_value("return_nested_float_struct")
225        # class test
226        self.return_and_test_struct_value("return_base_class_one_char")
227        self.return_and_test_struct_value("return_nested_class_float_and_base")
228        self.return_and_test_struct_value("return_double_nested_class_float_and_nested")
229        self.return_and_test_struct_value("return_base_class")
230        self.return_and_test_struct_value("return_derived_class")
231
232    @skipIf(compiler="clang", compiler_version=['<', '7.0'])
233    def return_and_test_struct_value(self, func_name):
234        """Pass in the name of the function to return from - takes in value, returns value."""
235
236        # Set the breakpoint, run to it, finish out.
237        bkpt = self.target.BreakpointCreateByName(func_name)
238        self.assertTrue(bkpt.GetNumResolvedLocations() > 0, "Got wrong number of locations for {0}".format(func_name))
239
240        self.process.Continue()
241
242        thread_list = lldbutil.get_threads_stopped_at_breakpoint(
243            self.process, bkpt)
244
245        self.assertEquals(len(thread_list), 1)
246        thread = thread_list[0]
247
248        self.target.BreakpointDelete(bkpt.GetID())
249
250        in_value = thread.GetFrameAtIndex(0).FindVariable("value")
251
252        self.assertTrue(in_value.IsValid())
253        num_in_children = in_value.GetNumChildren()
254
255        # This is a little hokey, but if we don't get all the children now, then
256        # once we've stepped we won't be able to get them?
257
258        for idx in range(0, num_in_children):
259            in_child = in_value.GetChildAtIndex(idx)
260            in_child_str = in_child.GetValue()
261
262        thread.StepOut()
263
264        self.assertState(self.process.GetState(), lldb.eStateStopped)
265        self.assertEquals(thread.GetStopReason(), lldb.eStopReasonPlanComplete)
266
267        # Assuming all these functions step out to main.  Could figure out the caller dynamically
268        # if that would add something to the test.
269        frame = thread.GetFrameAtIndex(0)
270        fun_name = frame.GetFunctionName()
271        self.assertEquals(fun_name, "main")
272
273        frame = thread.GetFrameAtIndex(0)
274        ret_value = thread.GetStopReturnValue()
275        if not self.should_report_return_value(func_name):
276            self.assertFalse(ret_value.IsValid(), "Shouldn't have gotten a value")
277            return
278
279        self.assertTrue(ret_value.IsValid())
280
281        num_ret_children = ret_value.GetNumChildren()
282        self.assertEquals(num_in_children, num_ret_children)
283        for idx in range(0, num_ret_children):
284            in_child = in_value.GetChildAtIndex(idx)
285            ret_child = ret_value.GetChildAtIndex(idx)
286            in_child_str = in_child.GetValue()
287            ret_child_str = ret_child.GetValue()
288
289            self.assertEqual(in_child_str, ret_child_str)
290