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