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)
{
}