diff options
19 files changed, 887 insertions, 267 deletions
diff --git a/lldb/include/lldb/Target/ABI.h b/lldb/include/lldb/Target/ABI.h index a98ab2a1915..722e38d23c8 100644 --- a/lldb/include/lldb/Target/ABI.h +++ b/lldb/include/lldb/Target/ABI.h @@ -45,14 +45,19 @@ public: 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; diff --git a/lldb/include/lldb/Target/ThreadPlanCallFunction.h b/lldb/include/lldb/Target/ThreadPlanCallFunction.h index 16d249d56ce..dde1d6780fd 100644 --- a/lldb/include/lldb/Target/ThreadPlanCallFunction.h +++ b/lldb/include/lldb/Target/ThreadPlanCallFunction.h @@ -22,9 +22,13 @@ namespace lldb_private { 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 @@ public: 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 @@ public: // 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 @@ private: // 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; diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index e33e9412c91..f460fa1afcf 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -1709,12 +1709,9 @@ Debugger::FormatPrompt 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 @@ Debugger::SettingsController::global_settings_table[] = 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/lldb/source/Expression/ClangFunction.cpp b/lldb/source/Expression/ClangFunction.cpp index ceebe38e055..c583da90d3e 100644 --- a/lldb/source/Expression/ClangFunction.cpp +++ b/lldb/source/Expression/ClangFunction.cpp @@ -405,6 +405,7 @@ ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx, 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 @@ ClangFunction::FetchFunctionResults (ExecutionContext &exe_ctx, lldb::addr_t arg { // 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/lldb/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp b/lldb/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp index 6035b051559..3477695425f 100644 --- a/lldb/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp +++ b/lldb/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 @@ ABIMacOSX_arm::GetArgumentValues (Thread &thread, 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)) - { - 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)) + default: + return return_valobj_sp; + case 64: { - 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 diff --git a/lldb/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h b/lldb/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h index fc345004692..70809e0414b 100644 --- a/lldb/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h +++ b/lldb/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h @@ -41,10 +41,12 @@ public: 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/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp b/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp index b356d774d4d..a8f407d042b 100644 --- a/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp +++ b/lldb/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 @@ ABIMacOSX_i386::GetArgumentValues (Thread &thread, 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/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h b/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h index 8c98a4c8cb1..ec18678f131 100644 --- a/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h +++ b/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h @@ -51,9 +51,12 @@ public: 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/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp b/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp index f7f5c011828..ba71895cd7a 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 @@ -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 @@ ABISysV_x86_64::GetArgumentValues (Thread &thread, 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) { - void *value_type = value.GetClangType(); - bool is_signed; + 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) + { + // 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); - if (ClangASTContext::IsIntegerType (value_type, is_signed)) + 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++) { - // 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 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 3498610372b..04801e04e41 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 @@ -45,10 +45,15 @@ public: 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/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index 2354d91c470..8e7f8fd966f 100644 --- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/lldb/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 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, 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 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, 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 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, 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 @@ bool lldb_private::InferiorCallMunmap(Process *process, addr_t addr, { lldb::ThreadPlanSP call_plan_sp (new ThreadPlanCallFunction (*thread, munmap_range.GetBaseAddress(), + ClangASTType(), stop_other_threads, discard_on_error, &addr, diff --git a/lldb/source/Symbol/ClangASTContext.cpp b/lldb/source/Symbol/ClangASTContext.cpp index 49ac28b228c..a04f8ed46c9 100644 --- a/lldb/source/Symbol/ClangASTContext.cpp +++ b/lldb/source/Symbol/ClangASTContext.cpp @@ -5411,9 +5411,10 @@ ClangASTContext::IsIntegerType (clang_type_t clang_type, bool &is_signed) if (builtin_type) { if (builtin_type->isInteger()) + { is_signed = builtin_type->isSignedInteger(); - - return true; + return true; + } } return false; diff --git a/lldb/source/Target/ABI.cpp b/lldb/source/Target/ABI.cpp index f3a5404aa10..7d82ab17bc7 100644 --- a/lldb/source/Target/ABI.cpp +++ b/lldb/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 @@ ABI::GetRegisterInfoByKind (RegisterKind reg_kind, uint32_t reg_num, RegisterInf 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/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp index 6fe6ec7df5b..ae083c770e3 100644 --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -861,7 +861,7 @@ Thread::QueueThreadPlanForCallFunction (bool abort_other_plans, 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/lldb/source/Target/ThreadPlanCallFunction.cpp b/lldb/source/Target/ThreadPlanCallFunction.cpp index 2494c7cacfd..a5180613f9e 100644 --- a/lldb/source/Target/ThreadPlanCallFunction.cpp +++ b/lldb/source/Target/ThreadPlanCallFunction.cpp @@ -37,6 +37,7 @@ using namespace lldb_private; 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 @@ ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread, 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, 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 @@ ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread, 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 @@ ThreadPlanCallFunction::DoTakedown () 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/lldb/source/Target/ThreadPlanCallUserExpression.cpp b/lldb/source/Target/ThreadPlanCallUserExpression.cpp index 0499a7c7ce4..6352edb5311 100644 --- a/lldb/source/Target/ThreadPlanCallUserExpression.cpp +++ b/lldb/source/Target/ThreadPlanCallUserExpression.cpp @@ -44,7 +44,7 @@ ThreadPlanCallUserExpression::ThreadPlanCallUserExpression (Thread &thread, 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) { } diff --git a/lldb/test/functionalities/return-value/Makefile b/lldb/test/functionalities/return-value/Makefile new file mode 100644 index 00000000000..cb03eabfc27 --- /dev/null +++ b/lldb/test/functionalities/return-value/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../make + +C_SOURCES := call-func.c + +include $(LEVEL)/Makefile.rules diff --git a/lldb/test/functionalities/return-value/TestReturnValue.py b/lldb/test/functionalities/return-value/TestReturnValue.py new file mode 100644 index 00000000000..5f041732ea0 --- /dev/null +++ b/lldb/test/functionalities/return-value/TestReturnValue.py @@ -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() diff --git a/lldb/test/functionalities/return-value/call-func.c b/lldb/test/functionalities/return-value/call-func.c new file mode 100644 index 00000000000..98138710ea7 --- /dev/null +++ b/lldb/test/functionalities/return-value/call-func.c @@ -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; + +} |

