[Lldb-commits] [lldb] r147157 - in /lldb/trunk: include/lldb/Target/ source/Core/ source/Expression/ source/Plugins/ABI/MacOSX-arm/ source/Plugins/ABI/MacOSX-i386/ source/Plugins/ABI/SysV-x86_64/ source/Plugins/Process/Utility/ source/Symbol/ source/Target/ test/functionalities/return-value/
Jim Ingham
jingham at apple.com
Thu Dec 22 11:12:41 PST 2011
Author: jingham
Date: Thu Dec 22 13:12:40 2011
New Revision: 147157
URL: http://llvm.org/viewvc/llvm-project?rev=147157&view=rev
Log:
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.
Added:
lldb/trunk/test/functionalities/return-value/
lldb/trunk/test/functionalities/return-value/Makefile
lldb/trunk/test/functionalities/return-value/TestReturnValue.py
lldb/trunk/test/functionalities/return-value/call-func.c
Modified:
lldb/trunk/include/lldb/Target/ABI.h
lldb/trunk/include/lldb/Target/ThreadPlanCallFunction.h
lldb/trunk/source/Core/Debugger.cpp
lldb/trunk/source/Expression/ClangFunction.cpp
lldb/trunk/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp
lldb/trunk/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h
lldb/trunk/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp
lldb/trunk/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h
lldb/trunk/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
lldb/trunk/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h
lldb/trunk/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
lldb/trunk/source/Symbol/ClangASTContext.cpp
lldb/trunk/source/Target/ABI.cpp
lldb/trunk/source/Target/Thread.cpp
lldb/trunk/source/Target/ThreadPlanCallFunction.cpp
lldb/trunk/source/Target/ThreadPlanCallUserExpression.cpp
Modified: lldb/trunk/include/lldb/Target/ABI.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/ABI.h?rev=147157&r1=147156&r2=147157&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/ABI.h (original)
+++ lldb/trunk/include/lldb/Target/ABI.h Thu Dec 22 13:12:40 2011
@@ -45,14 +45,19 @@
GetArgumentValues (Thread &thread,
ValueList &values) const = 0;
- virtual bool
- GetReturnValue (Thread &thread,
- Value &value) const = 0;
-
- virtual lldb::ValueObjectSP
+public:
+ lldb::ValueObjectSP
GetReturnValueObject (Thread &thread,
- ClangASTType &type) const;
+ ClangASTType &type,
+ bool persistent = true) const;
+protected:
+ // This is the method the ABI will call to actually calculate the return value.
+ // Don't put it in a persistant value object, that will be done by the ABI::GetReturnValueObject.
+ virtual lldb::ValueObjectSP
+ GetReturnValueObjectImpl (Thread &thread,
+ ClangASTType &type) const = 0;
+public:
virtual bool
CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan) = 0;
Modified: lldb/trunk/include/lldb/Target/ThreadPlanCallFunction.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/ThreadPlanCallFunction.h?rev=147157&r1=147156&r2=147157&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/ThreadPlanCallFunction.h (original)
+++ lldb/trunk/include/lldb/Target/ThreadPlanCallFunction.h Thu Dec 22 13:12:40 2011
@@ -22,9 +22,13 @@
class ThreadPlanCallFunction : public ThreadPlan
{
+ // Create a thread plan to call a function at the address passed in the "function"
+ // argument. If you plan to call GetReturnValueObject, then pass in the
+ // return type, otherwise just pass in an invalid ClangASTType.
public:
ThreadPlanCallFunction (Thread &thread,
Address &function,
+ const ClangASTType &return_type,
lldb::addr_t arg,
bool stop_other_threads,
bool discard_on_error = true,
@@ -33,6 +37,7 @@
ThreadPlanCallFunction (Thread &thread,
Address &function,
+ const ClangASTType &return_type,
bool stop_other_threads,
bool discard_on_error,
lldb::addr_t *arg1_ptr = NULL,
@@ -90,16 +95,10 @@
// plan is complete, you can call "GetReturnValue()" to retrieve the value
// that was extracted.
- const lldb::ValueSP &
- GetReturnValue ()
+ virtual lldb::ValueObjectSP
+ GetReturnValueObject ()
{
- return m_return_value_sp;
- }
-
- void
- RequestReturnValue (lldb::ValueSP &return_value_sp)
- {
- m_return_value_sp = return_value_sp;
+ return m_return_valobj_sp;
}
// Return the stack pointer that the function received
@@ -165,7 +164,8 @@
// thread plans, but for reporting purposes,
// it's nice to know the real stop reason.
// This gets set in DoTakedown.
- lldb::ValueSP m_return_value_sp; // If this contains a valid pointer, use the ABI to extract values when complete
+ ClangASTType m_return_type;
+ lldb::ValueObjectSP m_return_valobj_sp; // If this contains a valid pointer, use the ABI to extract values when complete
bool m_takedown_done; // We want to ensure we only do the takedown once. This ensures that.
lldb::addr_t m_stop_address; // This is the address we stopped at. Also set in DoTakedown;
Modified: lldb/trunk/source/Core/Debugger.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/Debugger.cpp?rev=147157&r1=147156&r2=147157&view=diff
==============================================================================
--- lldb/trunk/source/Core/Debugger.cpp (original)
+++ lldb/trunk/source/Core/Debugger.cpp Thu Dec 22 13:12:40 2011
@@ -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}"\
Modified: lldb/trunk/source/Expression/ClangFunction.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/ClangFunction.cpp?rev=147157&r1=147156&r2=147157&view=diff
==============================================================================
--- lldb/trunk/source/Expression/ClangFunction.cpp (original)
+++ lldb/trunk/source/Expression/ClangFunction.cpp Thu Dec 22 13:12:40 2011
@@ -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)
Modified: lldb/trunk/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp?rev=147157&r1=147156&r2=147157&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp (original)
+++ lldb/trunk/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp Thu Dec 22 13:12:40 2011
@@ -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
-{
- switch (value.GetContextType())
+ValueObjectSP
+ABIMacOSX_arm::GetReturnValueObjectImpl (Thread &thread,
+ lldb_private::ClangASTType &ast_type) const
+{
+ 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;
- }
- }
- 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;
+ 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;
}
- 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
Modified: lldb/trunk/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h?rev=147157&r1=147156&r2=147157&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h (original)
+++ lldb/trunk/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h Thu Dec 22 13:12:40 2011
@@ -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);
Modified: lldb/trunk/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp?rev=147157&r1=147156&r2=147157&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp (original)
+++ lldb/trunk/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp Thu Dec 22 13:12:40 2011
@@ -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
-{
- switch (value.GetContextType())
+ValueObjectSP
+ABIMacOSX_i386::GetReturnValueObjectImpl (Thread &thread,
+ ClangASTType &ast_type) const
+{
+ 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
Modified: lldb/trunk/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h?rev=147157&r1=147156&r2=147157&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h (original)
+++ lldb/trunk/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h Thu Dec 22 13:12:40 2011
@@ -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);
Modified: lldb/trunk/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp?rev=147157&r1=147156&r2=147157&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp (original)
+++ lldb/trunk/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp Thu Dec 22 13:12:40 2011
@@ -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))
{
+ // 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)
+ {
default:
- return false;
- case Value::eContextTypeClangType:
+ 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))
+ {
+ DataExtractor data;
+ if (xmm0_value.GetData(data))
+ {
+ 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 (bit_width == 128)
{
- void *value_type = value.GetClangType();
- bool is_signed;
+ // 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;
+// }
+// }
- RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+ 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;
+ }
+
+ // 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);
- if (!reg_ctx)
- return false;
+ 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);
- if (ClangASTContext::IsIntegerType (value_type, is_signed))
+ // 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++)
{
- // For now, assume that the types in the AST values come from the Target's
- // scratch AST.
+ std::string name;
+ uint32_t field_bit_offset;
+ bool is_signed;
+ bool is_complex;
+ uint32_t count;
- clang::ASTContext *ast_context = thread.CalculateTarget()->GetScratchClangASTContext()->getASTContext();
+ 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;
+ }
- // Extract the register context so we can read arguments from registers
+ uint32_t field_byte_width = field_bit_width/8;
+ uint32_t field_byte_offset = field_bit_offset/8;
- size_t bit_width = ClangASTType::GetClangTypeBitWidth(ast_context, value_type);
- unsigned rax_id = reg_ctx->GetRegisterInfoByName("rax", 0)->kinds[eRegisterKindLLDB];
+
+ DataExtractor *copy_from_extractor = NULL;
+ uint32_t copy_from_offset = 0;
- switch (bit_width)
+ if (ClangASTContext::IsIntegerType (field_clang_type, is_signed) || ClangASTContext::IsPointerType (field_clang_type))
{
- 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);
+ 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
- value.GetScalar() = (uint8_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0) & 0xff);
- break;
+ {
+ // 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);
}
- 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
+
+ if (!is_memory)
{
- // not handled yet
- return false;
+ // 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);
}
}
- break;
+
+ 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 true;
+
+ return return_valobj_sp;
}
bool
Modified: lldb/trunk/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h?rev=147157&r1=147156&r2=147157&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h (original)
+++ lldb/trunk/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h Thu Dec 22 13:12:40 2011
@@ -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);
Modified: lldb/trunk/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp?rev=147157&r1=147156&r2=147157&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp Thu Dec 22 13:12:40 2011
@@ -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,
Modified: lldb/trunk/source/Symbol/ClangASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/ClangASTContext.cpp?rev=147157&r1=147156&r2=147157&view=diff
==============================================================================
--- lldb/trunk/source/Symbol/ClangASTContext.cpp (original)
+++ lldb/trunk/source/Symbol/ClangASTContext.cpp Thu Dec 22 13:12:40 2011
@@ -5411,9 +5411,10 @@
if (builtin_type)
{
if (builtin_type->isInteger())
+ {
is_signed = builtin_type->isSignedInteger();
-
- return true;
+ return true;
+ }
}
return false;
Modified: lldb/trunk/source/Target/ABI.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/ABI.cpp?rev=147157&r1=147156&r2=147157&view=diff
==============================================================================
--- lldb/trunk/source/Target/ABI.cpp (original)
+++ lldb/trunk/source/Target/ABI.cpp Thu Dec 22 13:12:40 2011
@@ -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;
}
Modified: lldb/trunk/source/Target/Thread.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Thread.cpp?rev=147157&r1=147156&r2=147157&view=diff
==============================================================================
--- lldb/trunk/source/Target/Thread.cpp (original)
+++ lldb/trunk/source/Target/Thread.cpp Thu Dec 22 13:12:40 2011
@@ -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();
}
Modified: lldb/trunk/source/Target/ThreadPlanCallFunction.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/ThreadPlanCallFunction.cpp?rev=147157&r1=147156&r2=147157&view=diff
==============================================================================
--- lldb/trunk/source/Target/ThreadPlanCallFunction.cpp (original)
+++ lldb/trunk/source/Target/ThreadPlanCallFunction.cpp Thu Dec 22 13:12:40 2011
@@ -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;
Modified: lldb/trunk/source/Target/ThreadPlanCallUserExpression.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/ThreadPlanCallUserExpression.cpp?rev=147157&r1=147156&r2=147157&view=diff
==============================================================================
--- lldb/trunk/source/Target/ThreadPlanCallUserExpression.cpp (original)
+++ lldb/trunk/source/Target/ThreadPlanCallUserExpression.cpp Thu Dec 22 13:12:40 2011
@@ -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)
{
}
Added: lldb/trunk/test/functionalities/return-value/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/return-value/Makefile?rev=147157&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/return-value/Makefile (added)
+++ lldb/trunk/test/functionalities/return-value/Makefile Thu Dec 22 13:12:40 2011
@@ -0,0 +1,5 @@
+LEVEL = ../../make
+
+C_SOURCES := call-func.c
+
+include $(LEVEL)/Makefile.rules
Added: lldb/trunk/test/functionalities/return-value/TestReturnValue.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/return-value/TestReturnValue.py?rev=147157&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/return-value/TestReturnValue.py (added)
+++ lldb/trunk/test/functionalities/return-value/TestReturnValue.py Thu Dec 22 13:12:40 2011
@@ -0,0 +1,127 @@
+"""
+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")
+ @python_api_test
+ def test_with_dsym_python(self):
+ """Test getting return values from stepping out with dsyms."""
+ self.buildDsym()
+ self.do_return_value()
+
+ @python_api_test
+ def test_with_dwarf_python(self):
+ """Test getting return values from stepping out."""
+ self.buildDwarf()
+ self.do_return_value()
+
+ def do_return_value(self):
+ """Test getting return values from stepping out."""
+ exe = os.path.join(os.getcwd(), "a.out")
+ error = lldb.SBError()
+
+ target = self.dbg.CreateTarget(exe)
+ self.assertTrue(target, VALID_TARGET)
+
+ inner_sint_bkpt = target.BreakpointCreateByName("inner_sint", exe)
+ self.assertTrue(inner_sint_bkpt, VALID_BREAKPOINT)
+
+ # Now launch the process, and do not stop at entry point.
+ process = target.LaunchSimple(None, None, os.getcwd())
+
+ self.assertTrue(process, PROCESS_IS_VALID)
+
+ # The stop reason of the thread should be breakpoint.
+ self.assertTrue(process.GetState() == lldb.eStateStopped,
+ STOPPED_DUE_TO_BREAKPOINT)
+
+ # Now finish, and make sure the return value is correct.
+ thread = lldbutil.get_stopped_thread (process, lldb.eStopReasonBreakpoint)
+
+ thread.StepOut();
+
+ self.assertTrue (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())
+
+ in_int = frame.FindVariable ("value").GetValueAsSigned(error)
+ self.assertTrue (error.Success())
+ 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:
+
+ process.Continue()
+ thread_list = lldbutil.get_threads_stopped_at_breakpoint (process, inner_sint_bkpt)
+ self.assertTrue(len(thread_list) == 1)
+ thread = thread_list[0]
+
+ 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 (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 (in_int == ret_int)
+
+ # Now try some simple returns that have different types:
+ inner_float_bkpt = target.BreakpointCreateByName("inner_float", exe)
+ self.assertTrue(inner_float_bkpt, VALID_BREAKPOINT)
+ process.Continue()
+ thread_list = lldbutil.get_threads_stopped_at_breakpoint (process, inner_float_bkpt)
+ self.assertTrue (len(thread_list) == 1)
+ thread = thread_list[0]
+
+ frame = thread.GetFrameAtIndex(0)
+ in_value = frame.FindVariable ("value")
+ in_float = float (in_value.GetValue())
+ thread.StepOut()
+
+ self.assertTrue (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)
+
+if __name__ == '__main__':
+ import atexit
+ lldb.SBDebugger.Initialize()
+ atexit.register(lambda: lldb.SBDebugger.Terminate())
+ unittest2.main()
Added: lldb/trunk/test/functionalities/return-value/call-func.c
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/return-value/call-func.c?rev=147157&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/return-value/call-func.c (added)
+++ lldb/trunk/test/functionalities/return-value/call-func.c Thu Dec 22 13:12:40 2011
@@ -0,0 +1,90 @@
+int
+inner_sint (int value)
+{
+ return value;
+}
+
+int
+outer_sint (int value)
+{
+ return inner_sint (value);
+}
+
+float
+inner_float (float value)
+{
+ return value;
+}
+
+float
+outer_float (float value)
+{
+ return inner_float(value);
+}
+
+double
+inner_double (double value)
+{
+ return value;
+}
+
+double
+outer_double (double value)
+{
+ return inner_double(value);
+}
+
+long double
+inner_long_double (long double value)
+{
+ return value;
+}
+
+long double
+outer_long_double (long double value)
+{
+ return inner_long_double(value);
+}
+
+struct
+large_return_struct
+{
+ long long first_long;
+ long long second_long;
+ long long third_long;
+ long long fourth_long;
+
+};
+
+struct large_return_struct
+return_large_struct (long long first, long long second, long long third, long long fourth)
+{
+ return (struct large_return_struct) {first, second, third, fourth};
+}
+
+int
+main ()
+{
+ int first_int = 123456;
+ int second_int = 234567;
+
+ outer_sint (first_int);
+ outer_sint (second_int);
+
+ float float_value = 12.34;
+
+ outer_float (float_value);
+
+ double double_value = -23.45;
+
+ outer_double (double_value);
+
+ long double long_double_value = -3456789.987654321;
+
+ outer_long_double (long_double_value);
+
+ return_large_struct (10, 20, 30, 40);
+
+ return 0;
+
+}
More information about the lldb-commits
mailing list