""" Test getting return-values correctly when stepping out """ import os, time import re import unittest2 import lldb, lldbutil from lldbtest import * class ReturnValueTestCase(TestBase): mydir = os.path.join("functionalities", "return-value") @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") @expectedFailurei386 @python_api_test @dsym_test def test_with_dsym_python(self): """Test getting return values from stepping out with dsyms.""" self.buildDsym() self.do_return_value() @expectedFailurei386 @python_api_test @dwarf_test def test_with_dwarf_python(self): """Test getting return values from stepping out.""" self.buildDwarf() self.do_return_value() def return_and_test_struct_value (self, func_name): """Pass in the name of the function to return from - takes in value, returns value.""" # Set the breakpoint, run to it, finish out. bkpt = self.target.BreakpointCreateByName (func_name) self.assertTrue (bkpt.GetNumResolvedLocations() > 0) self.process.Continue () thread_list = lldbutil.get_threads_stopped_at_breakpoint (self.process, bkpt) self.assertTrue (len(thread_list) == 1) thread = thread_list[0] self.target.BreakpointDelete (bkpt.GetID()) in_value = thread.GetFrameAtIndex(0).FindVariable ("value") self.assertTrue (in_value.IsValid()) num_in_children = in_value.GetNumChildren() # This is a little hokey, but if we don't get all the children now, then # once we've stepped we won't be able to get them? for idx in range(0, num_in_children): in_child = in_value.GetChildAtIndex (idx) in_child_str = in_child.GetValue() thread.StepOut() self.assertTrue (self.process.GetState() == lldb.eStateStopped) self.assertTrue (thread.GetStopReason() == lldb.eStopReasonPlanComplete) # Assuming all these functions step out to main. Could figure out the caller dynamically # if that would add something to the test. frame = thread.GetFrameAtIndex(0) fun_name = frame.GetFunctionName() self.assertTrue (fun_name == "main") frame = thread.GetFrameAtIndex(0) ret_value = thread.GetStopReturnValue() self.assertTrue (ret_value.IsValid()) num_ret_children = ret_value.GetNumChildren() self.assertTrue (num_in_children == num_ret_children) for idx in range(0, num_ret_children): in_child = in_value.GetChildAtIndex(idx) ret_child = ret_value.GetChildAtIndex(idx) in_child_str = in_child.GetValue() ret_child_str = ret_child.GetValue() self.assertTrue (in_child_str == ret_child_str) def do_return_value(self): """Test getting return values from stepping out.""" exe = os.path.join(os.getcwd(), "a.out") error = lldb.SBError() self.target = self.dbg.CreateTarget(exe) self.assertTrue(self.target, VALID_TARGET) inner_sint_bkpt = self.target.BreakpointCreateByName("inner_sint", exe) self.assertTrue(inner_sint_bkpt, VALID_BREAKPOINT) # Now launch the process, and do not stop at entry point. self.process = self.target.LaunchSimple(None, None, os.getcwd()) self.assertTrue(self.process, PROCESS_IS_VALID) # The stop reason of the thread should be breakpoint. self.assertTrue(self.process.GetState() == lldb.eStateStopped, STOPPED_DUE_TO_BREAKPOINT) # Now finish, and make sure the return value is correct. thread = lldbutil.get_stopped_thread (self.process, lldb.eStopReasonBreakpoint) # inner_sint returns the variable value, so capture that here: in_int = thread.GetFrameAtIndex(0).FindVariable ("value").GetValueAsSigned(error) self.assertTrue (error.Success()) thread.StepOut(); self.assertTrue (self.process.GetState() == lldb.eStateStopped) self.assertTrue (thread.GetStopReason() == lldb.eStopReasonPlanComplete) frame = thread.GetFrameAtIndex(0) fun_name = frame.GetFunctionName() self.assertTrue (fun_name == "outer_sint") return_value = thread.GetStopReturnValue() self.assertTrue (return_value.IsValid()) ret_int = return_value.GetValueAsSigned(error) self.assertTrue (error.Success()) self.assertTrue (in_int == ret_int) # Run again and we will stop in inner_sint the second time outer_sint is called. #Then test stepping out two frames at once: self.process.Continue() thread_list = lldbutil.get_threads_stopped_at_breakpoint (self.process, inner_sint_bkpt) self.assertTrue(len(thread_list) == 1) thread = thread_list[0] # We are done with the inner_sint breakpoint: self.target.BreakpointDelete (inner_sint_bkpt.GetID()) frame = thread.GetFrameAtIndex(1) fun_name = frame.GetFunctionName () self.assertTrue (fun_name == "outer_sint") in_int = frame.FindVariable ("value").GetValueAsSigned(error) self.assertTrue (error.Success()) thread.StepOutOfFrame (frame) self.assertTrue (self.process.GetState() == lldb.eStateStopped) self.assertTrue (thread.GetStopReason() == lldb.eStopReasonPlanComplete) frame = thread.GetFrameAtIndex(0) fun_name = frame.GetFunctionName() self.assertTrue (fun_name == "main") ret_value = thread.GetStopReturnValue() self.assertTrue (return_value.IsValid()) ret_int = ret_value.GetValueAsSigned (error) self.assertTrue (error.Success()) self.assertTrue (2 * in_int == ret_int) # Now try some simple returns that have different types: inner_float_bkpt = self.target.BreakpointCreateByName("inner_float", exe) self.assertTrue(inner_float_bkpt, VALID_BREAKPOINT) self.process.Continue() thread_list = lldbutil.get_threads_stopped_at_breakpoint (self.process, inner_float_bkpt) self.assertTrue (len(thread_list) == 1) thread = thread_list[0] self.target.BreakpointDelete (inner_float_bkpt.GetID()) frame = thread.GetFrameAtIndex(0) in_value = frame.FindVariable ("value") in_float = float (in_value.GetValue()) thread.StepOut() self.assertTrue (self.process.GetState() == lldb.eStateStopped) self.assertTrue (thread.GetStopReason() == lldb.eStopReasonPlanComplete) frame = thread.GetFrameAtIndex(0) fun_name = frame.GetFunctionName() self.assertTrue (fun_name == "outer_float") return_value = thread.GetStopReturnValue() self.assertTrue (return_value.IsValid()) return_float = float (return_value.GetValue()) self.assertTrue(in_float == return_float) self.return_and_test_struct_value ("return_one_int") self.return_and_test_struct_value ("return_two_int") self.return_and_test_struct_value ("return_three_int") self.return_and_test_struct_value ("return_four_int") self.return_and_test_struct_value ("return_five_int") self.return_and_test_struct_value ("return_two_double") self.return_and_test_struct_value ("return_one_double_two_float") self.return_and_test_struct_value ("return_one_int_one_float_one_int") self.return_and_test_struct_value ("return_one_pointer") self.return_and_test_struct_value ("return_two_pointer") self.return_and_test_struct_value ("return_one_float_one_pointer") self.return_and_test_struct_value ("return_one_int_one_pointer") self.return_and_test_struct_value ("return_three_short_one_float") self.return_and_test_struct_value ("return_one_int_one_double") self.return_and_test_struct_value ("return_one_int_one_double_one_int") self.return_and_test_struct_value ("return_one_short_one_double_one_short") self.return_and_test_struct_value ("return_one_float_one_int_one_float") self.return_and_test_struct_value ("return_two_float") # I am leaving out the packed test until we have a way to tell CLANG # about alignment when reading DWARF for packed types. #self.return_and_test_struct_value ("return_one_int_one_double_packed") self.return_and_test_struct_value ("return_one_int_one_long") # icc and gcc don't support this extension. if self.getCompiler().endswith('clang'): self.return_and_test_struct_value ("return_vector_size_float32") self.return_and_test_struct_value ("return_ext_vector_size_float32") if __name__ == '__main__': import atexit lldb.SBDebugger.Initialize() atexit.register(lambda: lldb.SBDebugger.Terminate()) unittest2.main()