Improve the x86_64 return value decoder to handle most structure returns.
Switch from GetReturnValue, which was hardly ever used, to GetReturnValueObject
which is much more convenient.
Return the "return value object" as a persistent variable if requested.


git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@147157 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Core/Debugger.cpp b/source/Core/Debugger.cpp
index e33e941..f460fa1 100644
--- a/source/Core/Debugger.cpp
+++ b/source/Core/Debugger.cpp
@@ -1709,12 +1709,9 @@
                                                 ValueObjectSP return_valobj_sp = StopInfo::GetReturnValueObject (stop_info_sp);
                                                 if (return_valobj_sp)
                                                 {
-                                                    cstr = return_valobj_sp->GetValueAsCString ();
-                                                    if (cstr && cstr[0])
-                                                    {
-                                                        s.PutCString(cstr);
-                                                        var_success = true;
-                                                    }
+                                                    ValueObject::DumpValueObjectOptions dump_options;
+                                                    ValueObject::DumpValueObject (s, return_valobj_sp.get(), dump_options);
+                                                    var_success = true;
                                                 }
                                             }
                                         }
@@ -2579,7 +2576,7 @@
     MODULE_WITH_FUNC\
     FILE_AND_LINE\
     "{, stop reason = ${thread.stop-reason}}"\
-    "{, return value = ${thread.return-value}}"\
+    "{\\nReturn value: ${thread.return-value}}"\
     "\\n"
 
 //#define DEFAULT_THREAD_FORMAT "thread #${thread.index}: tid = ${thread.id}"\
diff --git a/source/Expression/ClangFunction.cpp b/source/Expression/ClangFunction.cpp
index ceebe38..c583da9 100644
--- a/source/Expression/ClangFunction.cpp
+++ b/source/Expression/ClangFunction.cpp
@@ -405,6 +405,7 @@
     Address wrapper_address (NULL, func_addr);
     ThreadPlan *new_plan = new ThreadPlanCallFunction (*thread, 
                                                        wrapper_address,
+                                                       ClangASTType(),
                                                        args_addr,
                                                        stop_others, 
                                                        discard_on_error,
@@ -418,7 +419,8 @@
 {
     // Read the return value - it is the last field in the struct:
     // FIXME: How does clang tell us there's no return value?  We need to handle that case.
-    
+    // FIXME: Create our ThreadPlanCallFunction with the return ClangASTType, and then use GetReturnValueObject
+    // to fetch the value.  That way we can fetch any values we need.
     Process *process = exe_ctx.GetProcessPtr();
     
     if (process == NULL)
diff --git a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp
index 6035b05..3477695 100644
--- a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp
+++ b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp
@@ -16,6 +16,7 @@
 #include "lldb/Core/RegisterValue.h"
 #include "lldb/Core/Scalar.h"
 #include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObjectConstResult.h"
 #include "lldb/Symbol/ClangASTContext.h"
 #include "lldb/Symbol/UnwindPlan.h"
 #include "lldb/Target/Process.h"
@@ -417,85 +418,92 @@
     return true;
 }
 
-bool
-ABIMacOSX_arm::GetReturnValue (Thread &thread,
-                               Value &value) const
+ValueObjectSP
+ABIMacOSX_arm::GetReturnValueObjectImpl (Thread &thread,
+                               lldb_private::ClangASTType &ast_type) const
 {
-    switch (value.GetContextType())
+    Value value;
+    ValueObjectSP return_valobj_sp;
+    
+    void *value_type = ast_type.GetOpaqueQualType();
+    if (!value_type) 
+        return return_valobj_sp;
+    
+    clang::ASTContext *ast_context = ast_type.GetASTContext();
+    if (!ast_context)
+        return return_valobj_sp;
+
+    value.SetContext (Value::eContextTypeClangType, value_type);
+            
+    RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+    if (!reg_ctx)
+        return return_valobj_sp;
+        
+    bool is_signed;
+    
+    // Get the pointer to the first stack argument so we have a place to start 
+    // when reading data
+    
+    const RegisterInfo *r0_reg_info = reg_ctx->GetRegisterInfoByName("r0", 0);
+    if (ClangASTContext::IsIntegerType (value_type, is_signed))
     {
-        default:
-            return false;
-        case Value::eContextTypeClangType:
+        size_t bit_width = ClangASTType::GetClangTypeBitWidth(ast_context, value_type);
+        
+        switch (bit_width)
         {
-            // Extract the Clang AST context from the PC so that we can figure out type
-            // sizes
-            
-            clang::ASTContext *ast_context = thread.CalculateTarget()->GetScratchClangASTContext()->getASTContext();
-            
-            // Get the pointer to the first stack argument so we have a place to start 
-            // when reading data
-            
-            RegisterContext *reg_ctx = thread.GetRegisterContext().get();
-            
-            void *value_type = value.GetClangType();
-            bool is_signed;
-            
-            const RegisterInfo *r0_reg_info = reg_ctx->GetRegisterInfoByName("r0", 0);
-            if (ClangASTContext::IsIntegerType (value_type, is_signed))
+            default:
+                return return_valobj_sp;
+            case 64:
             {
-                size_t bit_width = ClangASTType::GetClangTypeBitWidth(ast_context, value_type);
-                
-                switch (bit_width)
-                {
-                    default:
-                        return false;
-                    case 64:
-                    {
-                        const RegisterInfo *r1_reg_info = reg_ctx->GetRegisterInfoByName("r1", 0);
-                        uint64_t raw_value;
-                        raw_value = reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT32_MAX;
-                        raw_value |= ((uint64_t)(reg_ctx->ReadRegisterAsUnsigned(r1_reg_info, 0) & UINT32_MAX)) << 32;
-                        if (is_signed)
-                            value.GetScalar() = (int64_t)raw_value;
-                        else
-                            value.GetScalar() = (uint64_t)raw_value;
-                    }
-                        break;
-                    case 32:
-                        if (is_signed)
-                            value.GetScalar() = (int32_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT32_MAX);
-                        else
-                            value.GetScalar() = (uint32_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT32_MAX);
-                        break;
-                    case 16:
-                        if (is_signed)
-                            value.GetScalar() = (int16_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT16_MAX);
-                        else
-                            value.GetScalar() = (uint16_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT16_MAX);
-                        break;
-                    case 8:
-                        if (is_signed)
-                            value.GetScalar() = (int8_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT8_MAX);
-                        else
-                            value.GetScalar() = (uint8_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT8_MAX);
-                        break;
-                }
+                const RegisterInfo *r1_reg_info = reg_ctx->GetRegisterInfoByName("r1", 0);
+                uint64_t raw_value;
+                raw_value = reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT32_MAX;
+                raw_value |= ((uint64_t)(reg_ctx->ReadRegisterAsUnsigned(r1_reg_info, 0) & UINT32_MAX)) << 32;
+                if (is_signed)
+                    value.GetScalar() = (int64_t)raw_value;
+                else
+                    value.GetScalar() = (uint64_t)raw_value;
             }
-            else if (ClangASTContext::IsPointerType (value_type))
-            {
-                uint32_t ptr = thread.GetRegisterContext()->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT32_MAX;
-                value.GetScalar() = ptr;
-            }
-            else
-            {
-                // not handled yet
-                return false;
-            }
+                break;
+            case 32:
+                if (is_signed)
+                    value.GetScalar() = (int32_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT32_MAX);
+                else
+                    value.GetScalar() = (uint32_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT32_MAX);
+                break;
+            case 16:
+                if (is_signed)
+                    value.GetScalar() = (int16_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT16_MAX);
+                else
+                    value.GetScalar() = (uint16_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT16_MAX);
+                break;
+            case 8:
+                if (is_signed)
+                    value.GetScalar() = (int8_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT8_MAX);
+                else
+                    value.GetScalar() = (uint8_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT8_MAX);
+                break;
         }
-            break;
+    }
+    else if (ClangASTContext::IsPointerType (value_type))
+    {
+        uint32_t ptr = thread.GetRegisterContext()->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT32_MAX;
+        value.GetScalar() = ptr;
+    }
+    else
+    {
+        // not handled yet
+        return return_valobj_sp;
     }
     
-    return true;
+    // If we get here, we have a valid Value, so make our ValueObject out of it:
+    
+    return_valobj_sp = ValueObjectConstResult::Create(
+                                    thread.GetStackFrameAtIndex(0).get(),
+                                    ast_type.GetASTContext(),
+                                    value,
+                                    ConstString(""));
+    return return_valobj_sp;
 }
 
 bool
diff --git a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h
index fc34500..70809e0 100644
--- a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h
+++ b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h
@@ -41,10 +41,12 @@
     GetArgumentValues (lldb_private::Thread &thread,
                        lldb_private::ValueList &values) const;
     
-    virtual bool
-    GetReturnValue (lldb_private::Thread &thread,
-                    lldb_private::Value &value) const;
+protected:
+    virtual lldb::ValueObjectSP
+    GetReturnValueObjectImpl (lldb_private::Thread &thread,
+                    lldb_private::ClangASTType &ast_type) const;
 
+public:
     virtual bool
     CreateFunctionEntryUnwindPlan (lldb_private::UnwindPlan &unwind_plan);
     
diff --git a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp
index b356d77..a8f407d 100644
--- a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp
+++ b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp
@@ -15,6 +15,7 @@
 #include "lldb/Core/PluginManager.h"
 #include "lldb/Core/RegisterValue.h"
 #include "lldb/Core/Scalar.h"
+#include "lldb/Core/ValueObjectConstResult.h"
 #include "lldb/Symbol/ClangASTContext.h"
 #include "lldb/Symbol/UnwindPlan.h"
 #include "lldb/Target/Process.h"
@@ -681,87 +682,91 @@
     return true;
 }
 
-bool
-ABIMacOSX_i386::GetReturnValue (Thread &thread,
-                                Value &value) const
+ValueObjectSP
+ABIMacOSX_i386::GetReturnValueObjectImpl (Thread &thread,
+                                ClangASTType &ast_type) const
 {
-    switch (value.GetContextType())
+    Value value;
+    ValueObjectSP return_valobj_sp;
+    
+    void *value_type = ast_type.GetOpaqueQualType();
+    if (!value_type) 
+        return return_valobj_sp;
+    
+    clang::ASTContext *ast_context = ast_type.GetASTContext();
+    if (!ast_context)
+        return return_valobj_sp;
+
+    value.SetContext (Value::eContextTypeClangType, value_type);
+    
+    RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+        if (!reg_ctx)
+        return return_valobj_sp;
+        
+    bool is_signed;
+            
+    if (ClangASTContext::IsIntegerType (value_type, is_signed))
     {
-        default:
-            return false;
-        case Value::eContextTypeClangType:
+        size_t bit_width = ClangASTType::GetClangTypeBitWidth(ast_context, value_type);
+        
+        unsigned eax_id = reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];
+        unsigned edx_id = reg_ctx->GetRegisterInfoByName("edx", 0)->kinds[eRegisterKindLLDB];
+        
+        switch (bit_width)
         {
-            // Extract the Clang AST context from the PC so that we can figure out type
-            // sizes
-            
-            clang::ASTContext *ast_context = thread.CalculateTarget()->GetScratchClangASTContext()->getASTContext();
-            
-            // Get the pointer to the first stack argument so we have a place to start 
-            // when reading data
-            
-            RegisterContext *reg_ctx = thread.GetRegisterContext().get();
-            
-            void *value_type = value.GetClangType();
-            bool is_signed;
-            
-            if (ClangASTContext::IsIntegerType (value_type, is_signed))
-            {
-                size_t bit_width = ClangASTType::GetClangTypeBitWidth(ast_context, value_type);
-                
-                unsigned eax_id = reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];
-                unsigned edx_id = reg_ctx->GetRegisterInfoByName("edx", 0)->kinds[eRegisterKindLLDB];
-                
-                switch (bit_width)
-                {
-                    default:
-                    case 128:
-                        // Scalar can't hold 128-bit literals, so we don't handle this
-                        return false;
-                    case 64:
-                        uint64_t raw_value;
-                        raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff;
-                        raw_value |= (thread.GetRegisterContext()->ReadRegisterAsUnsigned(edx_id, 0) & 0xffffffff) << 32;
-                        if (is_signed)
-                            value.GetScalar() = (int64_t)raw_value;
-                        else
-                            value.GetScalar() = (uint64_t)raw_value;
-                        break;
-                    case 32:
-                        if (is_signed)
-                            value.GetScalar() = (int32_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff);
-                        else
-                            value.GetScalar() = (uint32_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff);
-                        break;
-                    case 16:
-                        if (is_signed)
-                            value.GetScalar() = (int16_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffff);
-                        else
-                            value.GetScalar() = (uint16_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffff);
-                        break;
-                    case 8:
-                        if (is_signed)
-                            value.GetScalar() = (int8_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xff);
-                        else
-                            value.GetScalar() = (uint8_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xff);
-                        break;
-                }
-            }
-            else if (ClangASTContext::IsPointerType (value_type))
-            {
-                unsigned eax_id = reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];
-                uint32_t ptr = thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff;
-                value.GetScalar() = ptr;
-            }
-            else
-            {
-                // not handled yet
-                return false;
-            }
+            default:
+            case 128:
+                // Scalar can't hold 128-bit literals, so we don't handle this
+                return return_valobj_sp;
+            case 64:
+                uint64_t raw_value;
+                raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff;
+                raw_value |= (thread.GetRegisterContext()->ReadRegisterAsUnsigned(edx_id, 0) & 0xffffffff) << 32;
+                if (is_signed)
+                    value.GetScalar() = (int64_t)raw_value;
+                else
+                    value.GetScalar() = (uint64_t)raw_value;
+                break;
+            case 32:
+                if (is_signed)
+                    value.GetScalar() = (int32_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff);
+                else
+                    value.GetScalar() = (uint32_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff);
+                break;
+            case 16:
+                if (is_signed)
+                    value.GetScalar() = (int16_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffff);
+                else
+                    value.GetScalar() = (uint16_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffff);
+                break;
+            case 8:
+                if (is_signed)
+                    value.GetScalar() = (int8_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xff);
+                else
+                    value.GetScalar() = (uint8_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xff);
+                break;
         }
-            break;
+    }
+    else if (ClangASTContext::IsPointerType (value_type))
+    {
+        unsigned eax_id = reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];
+        uint32_t ptr = thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff;
+        value.GetScalar() = ptr;
+    }
+    else
+    {
+        // not handled yet
+        return return_valobj_sp;
     }
     
-    return true;
+    // If we get here, we have a valid Value, so make our ValueObject out of it:
+    
+    return_valobj_sp = ValueObjectConstResult::Create(
+                                    thread.GetStackFrameAtIndex(0).get(),
+                                    ast_type.GetASTContext(),
+                                    value,
+                                    ConstString(""));
+    return return_valobj_sp;
 }
 
 bool
diff --git a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h
index 8c98a4c..ec18678 100644
--- a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h
+++ b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h
@@ -51,9 +51,12 @@
     GetArgumentValues (lldb_private::Thread &thread,
                        lldb_private::ValueList &values) const;
     
-    virtual bool
-    GetReturnValue (lldb_private::Thread &thread,
-                    lldb_private::Value &value) const;
+protected:
+    virtual lldb::ValueObjectSP
+    GetReturnValueObjectImpl (lldb_private::Thread &thread,
+                    lldb_private::ClangASTType &ast_type) const;
+
+public:
 
     virtual bool
     CreateFunctionEntryUnwindPlan (lldb_private::UnwindPlan &unwind_plan);
diff --git a/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
index f7f5c01..ba71895 100644
--- a/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
+++ b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
@@ -17,6 +17,9 @@
 #include "lldb/Core/PluginManager.h"
 #include "lldb/Core/RegisterValue.h"
 #include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Core/ValueObjectRegister.h"
+#include "lldb/Core/ValueObjectMemory.h"
 #include "lldb/Symbol/ClangASTContext.h"
 #include "lldb/Symbol/UnwindPlan.h"
 #include "lldb/Target/Target.h"
@@ -547,83 +550,404 @@
     return true;
 }
 
-bool
-ABISysV_x86_64::GetReturnValue (Thread &thread,
-                                Value &value) const
+ValueObjectSP
+ABISysV_x86_64::GetReturnValueObjectSimple (Thread &thread,
+                                ClangASTType &ast_type) const
 {
-    switch (value.GetContextType())
+    ValueObjectSP return_valobj_sp;
+    Value value;
+    
+    clang_type_t value_type = ast_type.GetOpaqueQualType();
+    if (!value_type) 
+        return return_valobj_sp;
+    
+    clang::ASTContext *ast_context = ast_type.GetASTContext();
+    if (!ast_context)
+        return return_valobj_sp;
+
+    value.SetContext (Value::eContextTypeClangType, value_type);
+    
+    RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+    if (!reg_ctx)
+        return return_valobj_sp;
+    
+    bool is_signed;
+    bool is_complex;
+    uint32_t count;
+
+    if (ClangASTContext::IsIntegerType (value_type, is_signed))
     {
-        default:
-            return false;
-        case Value::eContextTypeClangType:
+        // For now, assume that the types in the AST values come from the Target's 
+        // scratch AST.    
+        
+        
+        // Extract the register context so we can read arguments from registers
+        
+        size_t bit_width = ClangASTType::GetClangTypeBitWidth(ast_context, value_type);
+        unsigned rax_id = reg_ctx->GetRegisterInfoByName("rax", 0)->kinds[eRegisterKindLLDB];
+        
+        switch (bit_width)
         {
-            void *value_type = value.GetClangType();
-            bool is_signed;
-            
-            RegisterContext *reg_ctx = thread.GetRegisterContext().get();
-            
-            if (!reg_ctx)
-                return false;
-            
-            if (ClangASTContext::IsIntegerType (value_type, is_signed))
+        default:
+        case 128:
+            // Scalar can't hold 128-bit literals, so we don't handle this
+            return return_valobj_sp;
+        case 64:
+            if (is_signed)
+                value.GetScalar() = (int64_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0));
+            else
+                value.GetScalar() = (uint64_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0));
+            break;
+        case 32:
+            if (is_signed)
+                value.GetScalar() = (int32_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0) & 0xffffffff);
+            else
+                value.GetScalar() = (uint32_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0) & 0xffffffff);
+            break;
+        case 16:
+            if (is_signed)
+                value.GetScalar() = (int16_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0) & 0xffff);
+            else
+                value.GetScalar() = (uint16_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0) & 0xffff);
+            break;
+        case 8:
+            if (is_signed)
+                value.GetScalar() = (int8_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0) & 0xff);
+            else
+                value.GetScalar() = (uint8_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0) & 0xff);
+            break;
+        }
+    }
+    else if (ClangASTContext::IsFloatingPointType(value_type, count, is_complex))
+    {
+        // Don't handle complex yet.
+        if (is_complex)
+            return return_valobj_sp;
+        
+        size_t bit_width = ClangASTType::GetClangTypeBitWidth(ast_context, value_type);
+        if (bit_width <= 64)
+        {
+            const RegisterInfo *xmm0_info = reg_ctx->GetRegisterInfoByName("xmm0", 0);
+            RegisterValue xmm0_value;
+            if (reg_ctx->ReadRegister (xmm0_info, xmm0_value))
             {
-                // For now, assume that the types in the AST values come from the Target's 
-                // scratch AST.    
-                
-                clang::ASTContext *ast_context = thread.CalculateTarget()->GetScratchClangASTContext()->getASTContext();
-                
-                // Extract the register context so we can read arguments from registers
-                
-                size_t bit_width = ClangASTType::GetClangTypeBitWidth(ast_context, value_type);
-                unsigned rax_id = reg_ctx->GetRegisterInfoByName("rax", 0)->kinds[eRegisterKindLLDB];
-                
-                switch (bit_width)
+                DataExtractor data;
+                if (xmm0_value.GetData(data))
                 {
-                default:
-                case 128:
-                    // Scalar can't hold 128-bit literals, so we don't handle this
-                    return false;
-                case 64:
-                    if (is_signed)
-                        value.GetScalar() = (int64_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0));
-                    else
-                        value.GetScalar() = (uint64_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0));
-                    break;
-                case 32:
-                    if (is_signed)
-                        value.GetScalar() = (int32_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0) & 0xffffffff);
-                    else
-                        value.GetScalar() = (uint32_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0) & 0xffffffff);
-                    break;
-                case 16:
-                    if (is_signed)
-                        value.GetScalar() = (int16_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0) & 0xffff);
-                    else
-                        value.GetScalar() = (uint16_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0) & 0xffff);
-                    break;
-                case 8:
-                    if (is_signed)
-                        value.GetScalar() = (int8_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0) & 0xff);
-                    else
-                        value.GetScalar() = (uint8_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0) & 0xff);
-                    break;
+                    uint32_t offset = 0;
+                    switch (bit_width)
+                    {
+                        default:
+                            return return_valobj_sp;
+                        case 32:
+                            value.GetScalar() = (float) data.GetFloat(&offset);
+                            break;
+                        case 64:
+                            value.GetScalar() = (double) data.GetDouble(&offset);
+                            break;
+                    }
                 }
             }
-            else if (ClangASTContext::IsPointerType (value_type))
-            {
-                unsigned rax_id = reg_ctx->GetRegisterInfoByName("rax", 0)->kinds[eRegisterKindLLDB];
-                value.GetScalar() = (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0);
-            }
-            else
-            {
-                // not handled yet
-                return false;
-            }
         }
-        break;
+        else if (bit_width == 128)
+        {
+            // FIXME: x86_64 returns long doubles in stmm0, which is in some 80 bit long double
+            // format, and so we'll have to write some code to convert that into 128 bit long doubles.
+//            const RegisterInfo *st0_info = reg_ctx->GetRegisterInfoByName("stmm0", 0);
+//            RegisterValue st0_value;
+//            if (reg_ctx->ReadRegister (st0_info, st0_value))
+//            {
+//                DataExtractor data;
+//                if (st0_value.GetData(data))
+//                {
+//                    uint32_t offset = 0;
+//                    value.GetScalar() = (long double) data.GetLongDouble (&offset);
+//                    return true;
+//                }
+//            }
+            
+            return return_valobj_sp;
+        }
+    }
+    else if (ClangASTContext::IsPointerType (value_type))
+    {
+        unsigned rax_id = reg_ctx->GetRegisterInfoByName("rax", 0)->kinds[eRegisterKindLLDB];
+        value.GetScalar() = (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0);
+    }
+    else
+    {
+        return return_valobj_sp;
     }
     
-    return true;
+    // If we get here, we have a valid Value, so make our ValueObject out of it:
+    
+    return_valobj_sp = ValueObjectConstResult::Create(
+                                    thread.GetStackFrameAtIndex(0).get(),
+                                    ast_type.GetASTContext(),
+                                    value,
+                                    ConstString(""));
+    return return_valobj_sp;
+}
+
+ValueObjectSP
+ABISysV_x86_64::GetReturnValueObjectImpl (Thread &thread,
+                      ClangASTType &ast_type) const
+{
+
+    ValueObjectSP return_valobj_sp;
+    
+    return_valobj_sp = GetReturnValueObjectSimple(thread, ast_type);
+    if (return_valobj_sp)
+        return return_valobj_sp;
+    
+    clang_type_t ret_value_type = ast_type.GetOpaqueQualType();
+    if (!ret_value_type) 
+        return return_valobj_sp;
+    
+    clang::ASTContext *ast_context = ast_type.GetASTContext();
+    if (!ast_context)
+        return return_valobj_sp;
+        
+    RegisterContextSP reg_ctx_sp = thread.GetRegisterContext();
+    if (!reg_ctx_sp)
+        return return_valobj_sp;
+        
+    size_t bit_width = ClangASTType::GetClangTypeBitWidth(ast_context, ret_value_type);
+    if (ClangASTContext::IsAggregateType(ret_value_type))
+    {
+        Target &target = thread.GetProcess().GetTarget();
+        bool is_memory = true;
+        if (bit_width <= 128)
+        {
+            ByteOrder target_byte_order = target.GetArchitecture().GetByteOrder();
+            DataBufferSP data_sp (new DataBufferHeap(16, 0));
+            DataExtractor return_ext (data_sp, 
+                                      target_byte_order, 
+                                      target.GetArchitecture().GetAddressByteSize());
+                                                           
+            const RegisterInfo *rax_info = reg_ctx_sp->GetRegisterInfoByName("rax", 0);
+            const RegisterInfo *rdx_info = reg_ctx_sp->GetRegisterInfoByName("rdx", 0);
+            const RegisterInfo *xmm0_info = reg_ctx_sp->GetRegisterInfoByName("xmm0", 0);
+            const RegisterInfo *xmm1_info = reg_ctx_sp->GetRegisterInfoByName("xmm1", 0);
+            
+            RegisterValue rax_value, rdx_value, xmm0_value, xmm1_value;
+            reg_ctx_sp->ReadRegister (rax_info, rax_value);
+            reg_ctx_sp->ReadRegister (rdx_info, rdx_value);
+            reg_ctx_sp->ReadRegister (xmm0_info, xmm0_value);
+            reg_ctx_sp->ReadRegister (xmm1_info, xmm1_value);
+
+            DataExtractor rax_data, rdx_data, xmm0_data, xmm1_data;
+            
+            rax_value.GetData(rax_data);
+            rdx_value.GetData(rdx_data);
+            xmm0_value.GetData(xmm0_data);
+            xmm1_value.GetData(xmm1_data);
+            
+            uint32_t fp_bytes = 0;       // Tracks how much of the xmm registers we've consumed so far
+            uint32_t integer_bytes = 0;  // Tracks how much of the rax/rds registers we've consumed so far
+            
+            uint32_t num_children = ClangASTContext::GetNumFields (ast_context, ret_value_type);
+            
+            // Since we are in the small struct regime, assume we are not in memory.
+            is_memory = false;
+            
+            for (uint32_t idx = 0; idx < num_children; idx++)
+            {
+                std::string name;
+                uint32_t field_bit_offset;
+                bool is_signed;
+                bool is_complex;
+                uint32_t count;
+                
+                clang_type_t field_clang_type = ClangASTContext::GetFieldAtIndex (ast_context, ret_value_type, idx, name, &field_bit_offset);
+                size_t field_bit_width = ClangASTType::GetClangTypeBitWidth(ast_context, field_clang_type);
+
+                // If there are any unaligned fields, this is stored in memory.
+                if (field_bit_offset % field_bit_width != 0)
+                {
+                    is_memory = true;
+                    break;
+                }
+                
+                uint32_t field_byte_width = field_bit_width/8;
+                uint32_t field_byte_offset = field_bit_offset/8;
+                
+
+                DataExtractor *copy_from_extractor = NULL;
+                uint32_t       copy_from_offset    = 0;
+                
+                if (ClangASTContext::IsIntegerType (field_clang_type, is_signed) || ClangASTContext::IsPointerType (field_clang_type))
+                {
+                    if (integer_bytes < 8)
+                    {
+                        if (integer_bytes + field_byte_width <= 8)
+                        {
+                            // This is in RAX, copy from register to our result structure:
+                            copy_from_extractor = &rax_data;
+                            copy_from_offset = integer_bytes;
+                            integer_bytes += field_byte_width;
+                        }
+                        else
+                        {
+                            // The next field wouldn't fit in the remaining space, so we pushed it to rdx.
+                            copy_from_extractor = &rdx_data;
+                            copy_from_offset = 0;
+                            integer_bytes = 8 + field_byte_width;
+                        
+                        }
+                    }
+                    else if (integer_bytes + field_byte_width <= 16)
+                    {
+                        copy_from_extractor = &rdx_data;
+                        copy_from_offset = integer_bytes - 8;
+                        integer_bytes += field_byte_width;
+                    }
+                    else
+                    {
+                        // The last field didn't fit.  I can't see how that would happen w/o the overall size being 
+                        // greater than 16 bytes.  For now, return a NULL return value object.
+                        return return_valobj_sp;
+                    }
+                }
+                else if (ClangASTContext::IsFloatingPointType (field_clang_type, count, is_complex))
+                {
+                    // Structs with long doubles are always passed in memory.
+                    if (field_bit_width == 128)
+                    {
+                        is_memory = true;
+                        break;
+                    }
+                    else if (field_bit_width == 64)
+                    {
+                        // These have to be in a single xmm register.
+                        if (fp_bytes == 0)
+                            copy_from_extractor = &xmm0_data;
+                        else
+                            copy_from_extractor = &xmm1_data;
+
+                        copy_from_offset = 0;
+                        fp_bytes += field_byte_width;
+                    }
+                    else if (field_bit_width == 32)
+                    {
+                        // This one is kind of complicated.  If we are in an "eightbyte" with another float, we'll
+                        // be stuffed into an xmm register with it.  If we are in an "eightbyte" with one or more ints,
+                        // then we will be stuffed into the appropriate GPR with them.
+                        bool in_gpr;
+                        if (field_byte_offset % 8 == 0) 
+                        {
+                            // We are at the beginning of one of the eightbytes, so check the next element (if any)
+                            if (idx == num_children - 1)
+                                in_gpr = true;
+                            else
+                            {
+                                uint32_t next_field_bit_offset;
+                                clang_type_t next_field_clang_type = ClangASTContext::GetFieldAtIndex (ast_context, 
+                                                                                                       ret_value_type, 
+                                                                                                       idx + 1, 
+                                                                                                       name, 
+                                                                                                       &next_field_bit_offset);
+                                if (ClangASTContext::IsIntegerType (next_field_clang_type, is_signed))
+                                    in_gpr = true;
+                                else
+                                {
+                                    copy_from_offset = 0;
+                                    in_gpr = false;
+                                }
+                            }
+                                
+                        }
+                        else if (field_byte_offset % 4 == 0)
+                        {
+                            // We are inside of an eightbyte, so see if the field before us is floating point:
+                            // This could happen if somebody put padding in the structure.
+                            if (idx == 0)
+                                in_gpr = false;
+                            else
+                            {
+                                uint32_t prev_field_bit_offset;
+                                clang_type_t prev_field_clang_type = ClangASTContext::GetFieldAtIndex (ast_context, 
+                                                                                                       ret_value_type, 
+                                                                                                       idx - 1, 
+                                                                                                       name, 
+                                                                                                       &prev_field_bit_offset);
+                                if (ClangASTContext::IsIntegerType (prev_field_clang_type, is_signed))
+                                    in_gpr = true;
+                                else
+                                {
+                                    copy_from_offset = 4;
+                                    in_gpr = false;
+                                }
+                            }
+                            
+                        }
+                        else
+                        {
+                            is_memory = true;
+                            continue;
+                        }
+                        
+                        // Okay, we've figured out whether we are in GPR or XMM, now figure out which one.
+                        if (in_gpr)
+                        {
+                            if (integer_bytes < 8)
+                            {
+                                // This is in RAX, copy from register to our result structure:
+                                copy_from_extractor = &rax_data;
+                                copy_from_offset = integer_bytes;
+                                integer_bytes += field_byte_width;
+                            }
+                            else
+                            {
+                                copy_from_extractor = &rdx_data;
+                                copy_from_offset = integer_bytes - 8;
+                                integer_bytes += field_byte_width;
+                            }
+                        }
+                        else
+                        {
+                            if (fp_bytes < 8)
+                                copy_from_extractor = &xmm0_data;
+                            else
+                                copy_from_extractor = &xmm1_data;
+
+                            fp_bytes += field_byte_width;
+                        }
+                    } 
+                }
+                if (!copy_from_extractor)
+                    return return_valobj_sp;
+                    
+                copy_from_extractor->CopyByteOrderedData (copy_from_offset, 
+                                                          field_byte_width, 
+                                                          data_sp->GetBytes() + field_byte_offset, 
+                                                          field_byte_width, 
+                                                          target_byte_order);
+            }
+            
+            if (!is_memory)
+            {
+                // The result is in our data buffer.  Let's make a variable object out of it:
+                return_valobj_sp = ValueObjectConstResult::Create (&thread, 
+                                                                   ast_context, 
+                                                                   ret_value_type, 
+                                                                   ConstString(""),
+                                                                   return_ext);
+            }
+        }
+        
+        if (is_memory)
+        {
+            unsigned rax_id = reg_ctx_sp->GetRegisterInfoByName("rax", 0)->kinds[eRegisterKindLLDB];
+            lldb::addr_t storage_addr = (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0);
+            return_valobj_sp = ValueObjectMemory::Create (&thread,
+                                                          "",
+                                                          Address (storage_addr, NULL),
+                                                          ast_type); 
+        }
+    }
+        
+    return return_valobj_sp;
 }
 
 bool
diff --git a/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h
index 3498610..04801e0 100644
--- a/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h
+++ b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h
@@ -45,10 +45,15 @@
     GetArgumentValues (lldb_private::Thread &thread,
                        lldb_private::ValueList &values) const;
     
-    virtual bool
-    GetReturnValue (lldb_private::Thread &thread,
-                    lldb_private::Value &value) const;
-    
+protected:
+    lldb::ValueObjectSP
+    GetReturnValueObjectSimple (lldb_private::Thread &thread,
+                    lldb_private::ClangASTType &ast_type) const;
+public:    
+    virtual lldb::ValueObjectSP
+    GetReturnValueObjectImpl (lldb_private::Thread &thread,
+                          lldb_private::ClangASTType &type) const;
+
     virtual bool
     CreateFunctionEntryUnwindPlan (lldb_private::UnwindPlan &unwind_plan);
     
diff --git a/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
index 2354d91..8e7f8fd 100644
--- a/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
+++ b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
@@ -9,7 +9,7 @@
 
 #include "InferiorCallPOSIX.h"
 #include "lldb/Core/StreamFile.h"
-#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObject.h"
 #include "lldb/Symbol/SymbolContext.h"
 #include "lldb/Target/ExecutionContext.h"
 #include "lldb/Target/Process.h"
@@ -70,9 +70,12 @@
             AddressRange mmap_range;
             if (sc.GetAddressRange(range_scope, 0, use_inline_block_range, mmap_range))
             {
+                ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext();
+                lldb::clang_type_t clang_void_ptr_type = clang_ast_context->GetVoidPtrType(false);
                 ThreadPlanCallFunction *call_function_thread_plan
                   = new ThreadPlanCallFunction (*thread,
                                                 mmap_range.GetBaseAddress(),
+                                                ClangASTType (clang_ast_context->getASTContext(), clang_void_ptr_type),
                                                 stop_other_threads,
                                                 discard_on_error,
                                                 &addr,
@@ -84,13 +87,6 @@
                 lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan);
                 if (call_plan_sp)
                 {
-                    ValueSP return_value_sp (new Value);
-                    ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext();
-                    lldb::clang_type_t clang_void_ptr_type = clang_ast_context->GetVoidPtrType(false);
-                    return_value_sp->SetValueType (Value::eValueTypeScalar);
-                    return_value_sp->SetContext (Value::eContextTypeClangType, clang_void_ptr_type);
-                    call_function_thread_plan->RequestReturnValue (return_value_sp);
-
                     StreamFile error_strm;
                     StackFrame *frame = thread->GetStackFrameAtIndex (0).get();
                     if (frame)
@@ -106,7 +102,8 @@
                                                                           error_strm);
                         if (result == eExecutionCompleted)
                         {
-                            allocated_addr = return_value_sp->GetScalar().ULongLong();
+                            
+                            allocated_addr = call_plan_sp->GetReturnValueObject()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
                             if (process->GetAddressByteSize() == 4)
                             {
                                 if (allocated_addr == UINT32_MAX)
@@ -155,6 +152,7 @@
            {
                lldb::ThreadPlanSP call_plan_sp (new ThreadPlanCallFunction (*thread,
                                                                             munmap_range.GetBaseAddress(),
+                                                                            ClangASTType(),
                                                                             stop_other_threads,
                                                                             discard_on_error,
                                                                             &addr,
diff --git a/source/Symbol/ClangASTContext.cpp b/source/Symbol/ClangASTContext.cpp
index 49ac28b..a04f8ed 100644
--- a/source/Symbol/ClangASTContext.cpp
+++ b/source/Symbol/ClangASTContext.cpp
@@ -5411,9 +5411,10 @@
     if (builtin_type)
     {
         if (builtin_type->isInteger())
+        {
             is_signed = builtin_type->isSignedInteger();
-        
-        return true;
+            return true;
+        }
     }
     
     return false;
diff --git a/source/Target/ABI.cpp b/source/Target/ABI.cpp
index f3a5404..7d82ab1 100644
--- a/source/Target/ABI.cpp
+++ b/source/Target/ABI.cpp
@@ -12,6 +12,7 @@
 #include "lldb/Core/Value.h"
 #include "lldb/Core/ValueObjectConstResult.h"
 #include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Target/Target.h"
 #include "lldb/Target/Thread.h"
 
 using namespace lldb;
@@ -104,25 +105,69 @@
 
 ValueObjectSP
 ABI::GetReturnValueObject (Thread &thread,
-                          ClangASTType &ast_type) const
+                          ClangASTType &ast_type,
+                          bool persistent) const
 {
     if (!ast_type.IsValid())
         return ValueObjectSP();
         
-    Value ret_value;
-    ret_value.SetContext(Value::eContextTypeClangType, 
-                       ast_type.GetOpaqueQualType());
-    if (GetReturnValue (thread, ret_value))
+    ValueObjectSP return_valobj_sp;
+        
+    return_valobj_sp = GetReturnValueObjectImpl(thread, ast_type);
+    if (!return_valobj_sp)
+        return return_valobj_sp;
+    
+    // Now turn this into a persistent variable.
+    // FIXME: This code is duplicated from Target::EvaluateExpression, and it is used in similar form in a couple
+    // of other places.  Figure out the correct Create function to do all this work.
+    
+    if (persistent)
     {
-        return ValueObjectConstResult::Create(
-                                        thread.GetStackFrameAtIndex(0).get(),
-                                        ast_type.GetASTContext(),
-                                        ret_value,
-                                        ConstString("FunctionReturn"));
+        ClangPersistentVariables& persistent_variables = thread.GetProcess().GetTarget().GetPersistentVariables();
+        ConstString persistent_variable_name (persistent_variables.GetNextPersistentVariableName());
+
+        lldb::ValueObjectSP const_valobj_sp;
+        
+        // Check in case our value is already a constant value
+        if (return_valobj_sp->GetIsConstant())
+        {
+            const_valobj_sp = return_valobj_sp;
+            const_valobj_sp->SetName (persistent_variable_name);
+        }
+        else
+            const_valobj_sp = return_valobj_sp->CreateConstantValue (persistent_variable_name);
+
+        lldb::ValueObjectSP live_valobj_sp = return_valobj_sp;
+        
+        return_valobj_sp = const_valobj_sp;
+
+        ClangExpressionVariableSP clang_expr_variable_sp(persistent_variables.CreatePersistentVariable(return_valobj_sp));
+               
+        assert (clang_expr_variable_sp.get());
+        
+        // Set flags and live data as appropriate
+
+        const Value &result_value = live_valobj_sp->GetValue();
+        
+        switch (result_value.GetValueType())
+        {
+        case Value::eValueTypeHostAddress:
+        case Value::eValueTypeFileAddress:
+            // we don't do anything with these for now
+            break;
+        case Value::eValueTypeScalar:
+            clang_expr_variable_sp->m_flags |= ClangExpressionVariable::EVIsLLDBAllocated;
+            clang_expr_variable_sp->m_flags |= ClangExpressionVariable::EVNeedsAllocation;
+            break;
+        case Value::eValueTypeLoadAddress:
+            clang_expr_variable_sp->m_live_sp = live_valobj_sp;
+            clang_expr_variable_sp->m_flags |= ClangExpressionVariable::EVIsProgramReference;
+            break;
+        }
+        return_valobj_sp = clang_expr_variable_sp->GetValueObject();
 
     }
-    else
-        return ValueObjectSP();
+    return return_valobj_sp;
 }
 
 
diff --git a/source/Target/Thread.cpp b/source/Target/Thread.cpp
index 6fe6ec7..ae083c7 100644
--- a/source/Target/Thread.cpp
+++ b/source/Target/Thread.cpp
@@ -861,7 +861,7 @@
                                         bool stop_other_threads,
                                         bool discard_on_error)
 {
-    ThreadPlanSP thread_plan_sp (new ThreadPlanCallFunction (*this, function, arg, stop_other_threads, discard_on_error));
+    ThreadPlanSP thread_plan_sp (new ThreadPlanCallFunction (*this, function, ClangASTType(), arg, stop_other_threads, discard_on_error));
     QueueThreadPlan (thread_plan_sp, abort_other_plans);
     return thread_plan_sp.get();
 }
diff --git a/source/Target/ThreadPlanCallFunction.cpp b/source/Target/ThreadPlanCallFunction.cpp
index 2494c7c..a518061 100644
--- a/source/Target/ThreadPlanCallFunction.cpp
+++ b/source/Target/ThreadPlanCallFunction.cpp
@@ -37,6 +37,7 @@
 
 ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
                                                 Address &function,
+                                                const ClangASTType &return_type,
                                                 addr_t arg,
                                                 bool stop_other_threads,
                                                 bool discard_on_error,
@@ -47,6 +48,7 @@
     m_stop_other_threads (stop_other_threads),
     m_function_addr (function),
     m_function_sp (NULL),
+    m_return_type (return_type),
     m_takedown_done (false),
     m_stop_address (LLDB_INVALID_ADDRESS)
 {
@@ -149,6 +151,7 @@
 
 ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
                                                 Address &function,
+                                                const ClangASTType &return_type,
                                                 bool stop_other_threads,
                                                 bool discard_on_error,
                                                 addr_t *arg1_ptr,
@@ -162,6 +165,7 @@
     m_stop_other_threads (stop_other_threads),
     m_function_addr (function),
     m_function_sp(NULL),
+    m_return_type (return_type),
     m_takedown_done (false)
 {
     SetOkayToDiscard (discard_on_error);
@@ -281,13 +285,12 @@
     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
     if (!m_takedown_done)
     {
-        // TODO: how do we tell if all went well?
-        if (m_return_value_sp)
+        const ABI *abi = m_thread.GetProcess().GetABI().get();
+        if (abi && m_return_type.IsValid())
         {
-            const ABI *abi = m_thread.GetProcess().GetABI().get();
-            if (abi)
-                abi->GetReturnValue(m_thread, *m_return_value_sp);
+            m_return_valobj_sp = abi->GetReturnValueObject (m_thread, m_return_type);
         }
+
         if (log)
             log->Printf ("DoTakedown called for thread 0x%4.4llx, m_valid: %d complete: %d.\n", m_thread.GetID(), m_valid, IsPlanComplete());
         m_takedown_done = true;
diff --git a/source/Target/ThreadPlanCallUserExpression.cpp b/source/Target/ThreadPlanCallUserExpression.cpp
index 0499a7c..6352edb 100644
--- a/source/Target/ThreadPlanCallUserExpression.cpp
+++ b/source/Target/ThreadPlanCallUserExpression.cpp
@@ -44,7 +44,7 @@
                                                 lldb::addr_t *this_arg,
                                                 lldb::addr_t *cmd_arg,
                                                 ClangUserExpression::ClangUserExpressionSP &user_expression_sp) :
-    ThreadPlanCallFunction (thread, function, arg, stop_other_threads, discard_on_error, this_arg, cmd_arg),
+    ThreadPlanCallFunction (thread, function, ClangASTType(), arg, stop_other_threads, discard_on_error, this_arg, cmd_arg),
     m_user_expression_sp (user_expression_sp)
 {
 }