From 1f51e60b743fe3abadc79b280937554f90a1aadc Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Thu, 27 Sep 2012 01:15:29 +0000 Subject: [PATCH] Implement returning integer values in "thread return" for arm, x86_64 and i386. Also returns floats & doubles on x86_64. llvm-svn: 164741 --- .../Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp | 79 +++++++++++- .../ABI/MacOSX-i386/ABIMacOSX_i386.cpp | 87 +++++++++++-- .../ABI/SysV-x86_64/ABISysV_x86_64.cpp | 119 +++++++++++++++--- .../Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h | 1 + lldb/source/Target/Thread.cpp | 30 ++++- 5 files changed, 287 insertions(+), 29 deletions(-) diff --git a/lldb/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp b/lldb/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp index 565819c6c7a2..391ee0fe00a5 100644 --- a/lldb/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp +++ b/lldb/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp @@ -508,10 +508,83 @@ ABIMacOSX_arm::GetReturnValueObjectImpl (Thread &thread, } Error -ABIMacOSX_arm::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value) +ABIMacOSX_arm::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value_sp) { - Error return_error("I can't do that yet Jim."); - return return_error; + Error error; + if (!new_value_sp) + { + error.SetErrorString("Empty value object for return value."); + return error; + } + + clang_type_t value_type = new_value_sp->GetClangType(); + if (!value_type) + { + error.SetErrorString ("Null clang type for return value."); + return error; + } + + clang::ASTContext *ast_context = new_value_sp->GetClangAST(); + if (!ast_context) + { + error.SetErrorString ("Null clang AST for return value."); + return error; + } + Thread *thread = frame_sp->GetThread().get(); + + bool is_signed; + uint32_t count; + bool is_complex; + + RegisterContext *reg_ctx = thread->GetRegisterContext().get(); + + bool set_it_simple = false; + if (ClangASTContext::IsIntegerType (value_type, is_signed) || ClangASTContext::IsPointerType(value_type)) + { + DataExtractor data; + size_t num_bytes = new_value_sp->GetData(data); + uint32_t offset = 0; + if (num_bytes <= 8) + { + const RegisterInfo *r0_info = reg_ctx->GetRegisterInfoByName("r0", 0); + if (num_bytes <= 4) + { + uint32_t raw_value = data.GetMaxU32(&offset, num_bytes); + + if (reg_ctx->WriteRegisterFromUnsigned (r0_info, raw_value)) + set_it_simple = true; + } + else + { + uint32_t raw_value = data.GetMaxU32(&offset, 4); + + if (reg_ctx->WriteRegisterFromUnsigned (r0_info, raw_value)) + { + const RegisterInfo *r1_info = reg_ctx->GetRegisterInfoByName("r1", 0); + uint32_t raw_value = data.GetMaxU32(&offset, num_bytes - offset); + + if (reg_ctx->WriteRegisterFromUnsigned (r1_info, raw_value)) + set_it_simple = true; + } + } + } + else + { + error.SetErrorString("We don't support returning longer than 64 bit integer values at present."); + } + } + else if (ClangASTContext::IsFloatingPointType (value_type, count, is_complex)) + { + if (is_complex) + error.SetErrorString ("We don't support returning complex values at present"); + else + error.SetErrorString ("We don't support returning float values at present"); + } + + if (!set_it_simple) + error.SetErrorString ("We only support setting simple integer return types at present."); + + return error; } bool diff --git a/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp b/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp index 384f0645d408..c2f674b5131c 100644 --- a/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp +++ b/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp @@ -687,6 +687,86 @@ ABIMacOSX_i386::GetArgumentValues (Thread &thread, return true; } +Error +ABIMacOSX_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value_sp) +{ + Error error; + if (!new_value_sp) + { + error.SetErrorString("Empty value object for return value."); + return error; + } + + clang_type_t value_type = new_value_sp->GetClangType(); + if (!value_type) + { + error.SetErrorString ("Null clang type for return value."); + return error; + } + + clang::ASTContext *ast_context = new_value_sp->GetClangAST(); + if (!ast_context) + { + error.SetErrorString ("Null clang AST for return value."); + return error; + } + Thread *thread = frame_sp->GetThread().get(); + + bool is_signed; + uint32_t count; + bool is_complex; + + RegisterContext *reg_ctx = thread->GetRegisterContext().get(); + + bool set_it_simple = false; + if (ClangASTContext::IsIntegerType (value_type, is_signed) || ClangASTContext::IsPointerType(value_type)) + { + DataExtractor data; + size_t num_bytes = new_value_sp->GetData(data); + uint32_t offset = 0; + if (num_bytes <= 8) + { + const RegisterInfo *eax_info = reg_ctx->GetRegisterInfoByName("eax", 0); + if (num_bytes <= 4) + { + uint32_t raw_value = data.GetMaxU32(&offset, num_bytes); + + if (reg_ctx->WriteRegisterFromUnsigned (eax_info, raw_value)) + set_it_simple = true; + } + else + { + uint32_t raw_value = data.GetMaxU32(&offset, 4); + + if (reg_ctx->WriteRegisterFromUnsigned (eax_info, raw_value)) + { + const RegisterInfo *edx_info = reg_ctx->GetRegisterInfoByName("edx", 0); + uint32_t raw_value = data.GetMaxU32(&offset, num_bytes - offset); + + if (reg_ctx->WriteRegisterFromUnsigned (edx_info, raw_value)) + set_it_simple = true; + } + } + } + else + { + error.SetErrorString("We don't support returning longer than 64 bit integer values at present."); + } + } + else if (ClangASTContext::IsFloatingPointType (value_type, count, is_complex)) + { + if (is_complex) + error.SetErrorString ("We don't support returning complex values at present"); + else + error.SetErrorString ("We don't support returning float values at present"); + } + + if (!set_it_simple) + error.SetErrorString ("We only support setting simple integer return types at present."); + + return error; +} + ValueObjectSP ABIMacOSX_i386::GetReturnValueObjectImpl (Thread &thread, ClangASTType &ast_type) const @@ -774,13 +854,6 @@ ABIMacOSX_i386::GetReturnValueObjectImpl (Thread &thread, return return_valobj_sp; } -Error -ABIMacOSX_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value) -{ - Error return_error("I can't do that yet Jim."); - return return_error; -} - bool ABIMacOSX_i386::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan) { diff --git a/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp b/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp index 82963b440dfd..7a5bd9dec4f6 100644 --- a/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp +++ b/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp @@ -550,6 +550,100 @@ ABISysV_x86_64::GetArgumentValues (Thread &thread, return true; } +Error +ABISysV_x86_64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value_sp) +{ + Error error; + if (!new_value_sp) + { + error.SetErrorString("Empty value object for return value."); + return error; + } + + clang_type_t value_type = new_value_sp->GetClangType(); + if (!value_type) + { + error.SetErrorString ("Null clang type for return value."); + return error; + } + + clang::ASTContext *ast_context = new_value_sp->GetClangAST(); + if (!ast_context) + { + error.SetErrorString ("Null clang AST for return value."); + return error; + } + Thread *thread = frame_sp->GetThread().get(); + + bool is_signed; + uint32_t count; + bool is_complex; + + RegisterContext *reg_ctx = thread->GetRegisterContext().get(); + + bool set_it_simple = false; + if (ClangASTContext::IsIntegerType (value_type, is_signed) || ClangASTContext::IsPointerType(value_type)) + { + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName("rax", 0); + + DataExtractor data; + size_t num_bytes = new_value_sp->GetData(data); + uint32_t offset = 0; + if (num_bytes <= 64) + { + uint64_t raw_value = data.GetMaxU64(&offset, num_bytes); + + if (reg_ctx->WriteRegisterFromUnsigned (reg_info, raw_value)) + set_it_simple = true; + } + else + { + error.SetErrorString("We don't support returning longer than 64 bit integer values at present."); + } + + } + else if (ClangASTContext::IsFloatingPointType (value_type, count, is_complex)) + { + if (is_complex) + error.SetErrorString ("We don't support returning complex values at present"); + else + { + 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; + DataExtractor data; + size_t num_bytes = new_value_sp->GetData(data); + + unsigned char buffer[16]; + ByteOrder byte_order = data.GetByteOrder(); + uint32_t return_bytes; + + return_bytes = data.CopyByteOrderedData (0, num_bytes, buffer, 16, byte_order); + xmm0_value.SetBytes(buffer, 16, byte_order); + reg_ctx->WriteRegister(xmm0_info, xmm0_value); + set_it_simple = true; + } + else + { + // FIXME - don't know how to do 80 bit long doubles yet. + error.SetErrorString ("We don't support returning float values > 64 bits at present"); + } + } + } + + if (!set_it_simple) + { + // Okay we've got a structure or something that doesn't fit in a simple register. + // We should figure out where it really goes, but we don't support this yet. + error.SetErrorString ("We only support setting simple integer and float return types at present."); + } + + return error; +} + + ValueObjectSP ABISysV_x86_64::GetReturnValueObjectSimple (Thread &thread, ClangASTType &ast_type) const @@ -584,7 +678,7 @@ ABISysV_x86_64::GetReturnValueObjectSimple (Thread &thread, // 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]; + uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned(reg_ctx->GetRegisterInfoByName("rax", 0), 0); switch (bit_width) { @@ -594,27 +688,27 @@ ABISysV_x86_64::GetReturnValueObjectSimple (Thread &thread, return return_valobj_sp; case 64: if (is_signed) - value.GetScalar() = (int64_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0)); + value.GetScalar() = (int64_t)(raw_value); else - value.GetScalar() = (uint64_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0)); + value.GetScalar() = (uint64_t)(raw_value); break; case 32: if (is_signed) - value.GetScalar() = (int32_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0) & 0xffffffff); + value.GetScalar() = (int32_t)(raw_value & 0xffffffff); else - value.GetScalar() = (uint32_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0) & 0xffffffff); + value.GetScalar() = (uint32_t)(raw_value & 0xffffffff); break; case 16: if (is_signed) - value.GetScalar() = (int16_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0) & 0xffff); + value.GetScalar() = (int16_t)(raw_value & 0xffff); else - value.GetScalar() = (uint16_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0) & 0xffff); + value.GetScalar() = (uint16_t)(raw_value & 0xffff); break; case 8: if (is_signed) - value.GetScalar() = (int8_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0) & 0xff); + value.GetScalar() = (int8_t)(raw_value & 0xff); else - value.GetScalar() = (uint8_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0) & 0xff); + value.GetScalar() = (uint8_t)(raw_value & 0xff); break; } } @@ -959,13 +1053,6 @@ ABISysV_x86_64::GetReturnValueObjectImpl (Thread &thread, ClangASTType &ast_type return return_valobj_sp; } -Error -ABISysV_x86_64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value) -{ - Error return_error("I can't do that yet Jim."); - return return_error; -} - bool ABISysV_x86_64::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan) { diff --git a/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h b/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h index 31c1f843706e..9efc24499486 100644 --- a/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h +++ b/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h @@ -52,6 +52,7 @@ protected: lldb::ValueObjectSP GetReturnValueObjectSimple (lldb_private::Thread &thread, lldb_private::ClangASTType &ast_type) const; + public: virtual lldb::ValueObjectSP GetReturnValueObjectImpl (lldb_private::Thread &thread, diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp index 5cffe2d2624c..ee3a8554da7c 100644 --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -15,6 +15,7 @@ #include "lldb/Core/StreamString.h" #include "lldb/Core/RegularExpression.h" #include "lldb/Host/Host.h" +#include "lldb/Symbol/Function.h" #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/ObjCLanguageRuntime.h" @@ -1313,14 +1314,37 @@ Thread::ReturnFromFrame (lldb::StackFrameSP frame_sp, lldb::ValueObjectSP return StackFrameSP older_frame_sp = thread->GetStackFrameAtIndex(older_frame_idx); if (return_value_sp) - { - // TODO: coerce the return_value_sp to the type of the function in frame_sp. - + { lldb::ABISP abi = thread->GetProcess()->GetABI(); if (!abi) { return_error.SetErrorString("Could not find ABI to set return value."); } + SymbolContext sc = frame_sp->GetSymbolContext(eSymbolContextFunction); + + // FIXME: ValueObject::Cast doesn't currently work correctly, at least not for scalars. + // Turn that back on when that works. + if (0 && sc.function != NULL) + { + Type *function_type = sc.function->GetType(); + if (function_type) + { + clang_type_t return_type = sc.function->GetReturnClangType(); + if (return_type) + { + ClangASTType ast_type (function_type->GetClangAST(), return_type); + StreamString s; + ast_type.DumpTypeDescription(&s); + ValueObjectSP cast_value_sp = return_value_sp->Cast(ast_type); + if (cast_value_sp) + { + cast_value_sp->SetFormat(eFormatHex); + return_value_sp = cast_value_sp; + } + } + } + } + return_error = abi->SetReturnValueObject(older_frame_sp, return_value_sp); if (!return_error.Success()) return return_error;