blob: 0559cba3354a6c2276288b6cb11ab753c002f06e [file] [log] [blame]
"""
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")
if __name__ == '__main__':
import atexit
lldb.SBDebugger.Initialize()
atexit.register(lambda: lldb.SBDebugger.Terminate())
unittest2.main()