1"""
2Test getting return-values correctly when stepping out
3"""
4
5import os, time
6import re
7import unittest2
8import lldb, lldbutil
9from lldbtest import *
10
11class ReturnValueTestCase(TestBase):
12
13    mydir = os.path.join("functionalities", "return-value")
14
15    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
16    @expectedFailurei386
17    @python_api_test
18    @dsym_test
19    def test_with_dsym_python(self):
20        """Test getting return values from stepping out with dsyms."""
21        self.buildDsym()
22        self.do_return_value()
23
24    @expectedFailurei386
25    @python_api_test
26    @dwarf_test
27    def test_with_dwarf_python(self):
28        """Test getting return values from stepping out."""
29        self.buildDwarf()
30        self.do_return_value()
31
32    def return_and_test_struct_value (self, func_name):
33        """Pass in the name of the function to return from - takes in value, returns value."""
34
35        # Set the breakpoint, run to it, finish out.
36        bkpt = self.target.BreakpointCreateByName (func_name)
37        self.assertTrue (bkpt.GetNumResolvedLocations() > 0)
38
39        self.process.Continue ()
40
41        thread_list = lldbutil.get_threads_stopped_at_breakpoint (self.process, bkpt)
42
43        self.assertTrue (len(thread_list) == 1)
44        thread = thread_list[0]
45
46        self.target.BreakpointDelete (bkpt.GetID())
47
48        in_value = thread.GetFrameAtIndex(0).FindVariable ("value")
49
50        self.assertTrue (in_value.IsValid())
51        num_in_children = in_value.GetNumChildren()
52
53        # This is a little hokey, but if we don't get all the children now, then
54        # once we've stepped we won't be able to get them?
55
56        for idx in range(0, num_in_children):
57            in_child = in_value.GetChildAtIndex (idx)
58            in_child_str = in_child.GetValue()
59
60        thread.StepOut()
61
62        self.assertTrue (self.process.GetState() == lldb.eStateStopped)
63        self.assertTrue (thread.GetStopReason() == lldb.eStopReasonPlanComplete)
64
65        # Assuming all these functions step out to main.  Could figure out the caller dynamically
66        # if that would add something to the test.
67        frame = thread.GetFrameAtIndex(0)
68        fun_name = frame.GetFunctionName()
69        self.assertTrue (fun_name == "main")
70
71        frame = thread.GetFrameAtIndex(0)
72        ret_value = thread.GetStopReturnValue()
73
74        self.assertTrue (ret_value.IsValid())
75
76        num_ret_children = ret_value.GetNumChildren()
77        self.assertTrue (num_in_children == num_ret_children)
78        for idx in range(0, num_ret_children):
79            in_child = in_value.GetChildAtIndex(idx)
80            ret_child = ret_value.GetChildAtIndex(idx)
81            in_child_str = in_child.GetValue()
82            ret_child_str = ret_child.GetValue()
83
84            self.assertTrue (in_child_str == ret_child_str)
85
86    def do_return_value(self):
87        """Test getting return values from stepping out."""
88        exe = os.path.join(os.getcwd(), "a.out")
89        error = lldb.SBError()
90
91        self.target = self.dbg.CreateTarget(exe)
92        self.assertTrue(self.target, VALID_TARGET)
93
94        inner_sint_bkpt = self.target.BreakpointCreateByName("inner_sint", exe)
95        self.assertTrue(inner_sint_bkpt, VALID_BREAKPOINT)
96
97        # Now launch the process, and do not stop at entry point.
98        self.process = self.target.LaunchSimple(None, None, os.getcwd())
99
100        self.assertTrue(self.process, PROCESS_IS_VALID)
101
102        # The stop reason of the thread should be breakpoint.
103        self.assertTrue(self.process.GetState() == lldb.eStateStopped,
104                        STOPPED_DUE_TO_BREAKPOINT)
105
106        # Now finish, and make sure the return value is correct.
107        thread = lldbutil.get_stopped_thread (self.process, lldb.eStopReasonBreakpoint)
108
109        # inner_sint returns the variable value, so capture that here:
110        in_int = thread.GetFrameAtIndex(0).FindVariable ("value").GetValueAsSigned(error)
111        self.assertTrue (error.Success())
112
113        thread.StepOut();
114
115        self.assertTrue (self.process.GetState() == lldb.eStateStopped)
116        self.assertTrue (thread.GetStopReason() == lldb.eStopReasonPlanComplete)
117
118        frame = thread.GetFrameAtIndex(0)
119        fun_name = frame.GetFunctionName()
120        self.assertTrue (fun_name == "outer_sint")
121
122        return_value = thread.GetStopReturnValue()
123        self.assertTrue (return_value.IsValid())
124
125        ret_int = return_value.GetValueAsSigned(error)
126        self.assertTrue (error.Success())
127        self.assertTrue (in_int == ret_int)
128
129        # Run again and we will stop in inner_sint the second time outer_sint is called.
130        #Then test stepping out two frames at once:
131
132        self.process.Continue()
133        thread_list = lldbutil.get_threads_stopped_at_breakpoint (self.process, inner_sint_bkpt)
134        self.assertTrue(len(thread_list) == 1)
135        thread = thread_list[0]
136
137        # We are done with the inner_sint breakpoint:
138        self.target.BreakpointDelete (inner_sint_bkpt.GetID())
139
140        frame = thread.GetFrameAtIndex(1)
141        fun_name = frame.GetFunctionName ()
142        self.assertTrue (fun_name == "outer_sint")
143        in_int = frame.FindVariable ("value").GetValueAsSigned(error)
144        self.assertTrue (error.Success())
145
146        thread.StepOutOfFrame (frame)
147
148        self.assertTrue (self.process.GetState() == lldb.eStateStopped)
149        self.assertTrue (thread.GetStopReason() == lldb.eStopReasonPlanComplete)
150        frame = thread.GetFrameAtIndex(0)
151        fun_name = frame.GetFunctionName()
152        self.assertTrue (fun_name == "main")
153
154        ret_value = thread.GetStopReturnValue()
155        self.assertTrue (return_value.IsValid())
156        ret_int = ret_value.GetValueAsSigned (error)
157        self.assertTrue (error.Success())
158        self.assertTrue (2 * in_int == ret_int)
159
160        # Now try some simple returns that have different types:
161        inner_float_bkpt = self.target.BreakpointCreateByName("inner_float", exe)
162        self.assertTrue(inner_float_bkpt, VALID_BREAKPOINT)
163        self.process.Continue()
164        thread_list = lldbutil.get_threads_stopped_at_breakpoint (self.process, inner_float_bkpt)
165        self.assertTrue (len(thread_list) == 1)
166        thread = thread_list[0]
167
168        self.target.BreakpointDelete (inner_float_bkpt.GetID())
169
170        frame = thread.GetFrameAtIndex(0)
171        in_value = frame.FindVariable ("value")
172        in_float = float (in_value.GetValue())
173        thread.StepOut()
174
175        self.assertTrue (self.process.GetState() == lldb.eStateStopped)
176        self.assertTrue (thread.GetStopReason() == lldb.eStopReasonPlanComplete)
177
178        frame = thread.GetFrameAtIndex(0)
179        fun_name = frame.GetFunctionName()
180        self.assertTrue (fun_name == "outer_float")
181
182        return_value = thread.GetStopReturnValue()
183        self.assertTrue (return_value.IsValid())
184        return_float = float (return_value.GetValue())
185
186        self.assertTrue(in_float == return_float)
187
188        self.return_and_test_struct_value ("return_one_int")
189        self.return_and_test_struct_value ("return_two_int")
190        self.return_and_test_struct_value ("return_three_int")
191        self.return_and_test_struct_value ("return_four_int")
192        self.return_and_test_struct_value ("return_five_int")
193
194        self.return_and_test_struct_value ("return_two_double")
195        self.return_and_test_struct_value ("return_one_double_two_float")
196        self.return_and_test_struct_value ("return_one_int_one_float_one_int")
197
198        self.return_and_test_struct_value ("return_one_pointer")
199        self.return_and_test_struct_value ("return_two_pointer")
200        self.return_and_test_struct_value ("return_one_float_one_pointer")
201        self.return_and_test_struct_value ("return_one_int_one_pointer")
202        self.return_and_test_struct_value ("return_three_short_one_float")
203
204        self.return_and_test_struct_value ("return_one_int_one_double")
205        self.return_and_test_struct_value ("return_one_int_one_double_one_int")
206        self.return_and_test_struct_value ("return_one_short_one_double_one_short")
207        self.return_and_test_struct_value ("return_one_float_one_int_one_float")
208        self.return_and_test_struct_value ("return_two_float")
209        # I am leaving out the packed test until we have a way to tell CLANG
210        # about alignment when reading DWARF for packed types.
211        #self.return_and_test_struct_value ("return_one_int_one_double_packed")
212        self.return_and_test_struct_value ("return_one_int_one_long")
213
214        # icc and gcc don't support this extension.
215        if self.getCompiler().endswith('clang'):
216            self.return_and_test_struct_value ("return_vector_size_float32")
217            self.return_and_test_struct_value ("return_ext_vector_size_float32")
218
219
220if __name__ == '__main__':
221    import atexit
222    lldb.SBDebugger.Initialize()
223    atexit.register(lambda: lldb.SBDebugger.Terminate())
224    unittest2.main()
225