diff options
| author | Abhishek Aggarwal <abhishek.a.aggarwal@intel.com> | 2015-09-04 07:44:05 +0000 |
|---|---|---|
| committer | Abhishek Aggarwal <abhishek.a.aggarwal@intel.com> | 2015-09-04 07:44:05 +0000 |
| commit | 2cf87a895d5b64c5c6e2c242f4e12ce2a8d68a94 (patch) | |
| tree | c2612d3894cea8b7e9379abb174cb75653ecfb2f /lldb/source/Plugins | |
| parent | 5ca46f0df128a6b3868f332fcfd4c10d01152c19 (diff) | |
| download | bcm5719-llvm-2cf87a895d5b64c5c6e2c242f4e12ce2a8d68a94.tar.gz bcm5719-llvm-2cf87a895d5b64c5c6e2c242f4e12ce2a8d68a94.zip | |
SysV ABI for i386 Architecture
Summary:
- Capability to force return user specified values
from inside of a function on lldb command terminal
- Support for Integral, Pointer and Floating Point values
Signed-off-by: Abhishek Aggarwal <abhishek.a.aggarwal@intel.com>
Reviewers: jingham, clayborg
Subscribers: tberghammer
Differential Revision: http://reviews.llvm.org/D12595
llvm-svn: 246841
Diffstat (limited to 'lldb/source/Plugins')
| -rwxr-xr-x[-rw-r--r--] | lldb/source/Plugins/ABI/SysV-i386/ABISysV_i386.cpp | 145 |
1 files changed, 143 insertions, 2 deletions
diff --git a/lldb/source/Plugins/ABI/SysV-i386/ABISysV_i386.cpp b/lldb/source/Plugins/ABI/SysV-i386/ABISysV_i386.cpp index c6f3fd2d32d..af439cdb35b 100644..100755 --- a/lldb/source/Plugins/ABI/SysV-i386/ABISysV_i386.cpp +++ b/lldb/source/Plugins/ABI/SysV-i386/ABISysV_i386.cpp @@ -418,8 +418,149 @@ Error ABISysV_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value_sp) { Error error; - //ToDo: Yet to be implemented - error.SetErrorString("ABISysV_i386::SetReturnValueObject(): Not implemented yet"); + if (!new_value_sp) + { + error.SetErrorString("Empty value object for return value."); + return error; + } + + CompilerType clang_type = new_value_sp->GetCompilerType(); + if (!clang_type) + { + error.SetErrorString ("Null clang type for return value."); + return error; + } + + const uint32_t type_flags = clang_type.GetTypeInfo (); + Thread *thread = frame_sp->GetThread().get(); + RegisterContext *reg_ctx = thread->GetRegisterContext().get(); + DataExtractor data; + Error data_error; + size_t num_bytes = new_value_sp->GetData(data, data_error); + bool register_write_successful = true; + + if (data_error.Fail()) + { + error.SetErrorStringWithFormat("Couldn't convert return value to raw data: %s", data_error.AsCString()); + return error; + } + + // Following "IF ELSE" block categorizes various 'Fundamental Data Types'. + // The terminology 'Fundamental Data Types' used here is adopted from + // Table 2.1 of the reference document (specified on top of this file) + + if (type_flags & eTypeIsPointer) // 'Pointer' + { + if(num_bytes != sizeof(uint32_t)) + { + error.SetErrorString("Pointer to be returned is not 4 bytes wide"); + return error; + } + lldb::offset_t offset = 0; + const RegisterInfo *eax_info = reg_ctx->GetRegisterInfoByName("eax", 0); + uint32_t raw_value = data.GetMaxU32(&offset, num_bytes); + register_write_successful = reg_ctx->WriteRegisterFromUnsigned (eax_info, raw_value); + } + else if ((type_flags & eTypeIsScalar) || (type_flags & eTypeIsEnumeration)) //'Integral' + 'Floating Point' + { + lldb::offset_t offset = 0; + const RegisterInfo *eax_info = reg_ctx->GetRegisterInfoByName("eax", 0); + + if (type_flags & eTypeIsInteger) // 'Integral' except enum + { + switch (num_bytes) + { + default: + break; + case 16: + // For clang::BuiltinType::UInt128 & Int128 + // ToDo: Need to decide how to handle it + break; + case 8: + { + uint32_t raw_value_low = data.GetMaxU32(&offset, 4); + const RegisterInfo *edx_info = reg_ctx->GetRegisterInfoByName("edx", 0); + uint32_t raw_value_high = data.GetMaxU32(&offset, num_bytes - offset); + register_write_successful = (reg_ctx->WriteRegisterFromUnsigned (eax_info, raw_value_low) && + reg_ctx->WriteRegisterFromUnsigned (edx_info, raw_value_high)); + break; + } + case 4: + case 2: + case 1: + { + uint32_t raw_value = data.GetMaxU32(&offset, num_bytes); + register_write_successful = reg_ctx->WriteRegisterFromUnsigned (eax_info, raw_value); + break; + } + } + } + else if (type_flags & eTypeIsEnumeration) // handles enum + { + uint32_t raw_value = data.GetMaxU32(&offset, num_bytes); + register_write_successful = reg_ctx->WriteRegisterFromUnsigned (eax_info, raw_value); + } + else if (type_flags & eTypeIsFloat) // 'Floating Point' + { + RegisterValue st0_value, fstat_value, ftag_value; + const RegisterInfo *st0_info = reg_ctx->GetRegisterInfoByName("st0", 0); + const RegisterInfo *fstat_info = reg_ctx->GetRegisterInfoByName("fstat", 0); + const RegisterInfo *ftag_info = reg_ctx->GetRegisterInfoByName("ftag", 0); + + /* According to Page 3-12 of document + System V Application Binary Interface, Intel386 Architecture Processor Supplement, Fourth Edition + To return Floating Point values, all st% registers except st0 should be empty after exiting from + a function. This requires setting fstat and ftag registers to specific values. + fstat: The TOP field of fstat should be set to a value [0,7]. ABI doesn't specify the specific + value of TOP in case of function return. Hence, we set the TOP field to 7 by our choice. */ + uint32_t value_fstat_u32 = 0x00003800; + + /* ftag: Implication of setting TOP to 7 and indicating all st% registers empty except st0 is to set + 7th bit of 4th byte of FXSAVE area to 1 and all other bits of this byte to 0. This is in accordance + with the document Intel 64 and IA-32 Architectures Software Developer's Manual, January 2015 */ + uint32_t value_ftag_u32 = 0x00000080; + + if (num_bytes <= 12) // handles float, double, long double, __float80 + { + long double value_long_dbl = 0.0; + if (num_bytes == 4) + value_long_dbl = data.GetFloat(&offset); + else if (num_bytes == 8) + value_long_dbl = data.GetDouble(&offset); + else if (num_bytes == 12) + value_long_dbl = data.GetLongDouble(&offset); + else + { + error.SetErrorString ("Invalid number of bytes for this return type"); + return error; + } + st0_value.SetLongDouble(value_long_dbl); + fstat_value.SetUInt32(value_fstat_u32); + ftag_value.SetUInt32(value_ftag_u32); + register_write_successful = reg_ctx->WriteRegister(st0_info, st0_value) && + reg_ctx->WriteRegister(fstat_info, fstat_value) && + reg_ctx->WriteRegister(ftag_info, ftag_value); + } + else if(num_bytes == 16) // handles __float128 + { + error.SetErrorString ("Implementation is missing for this clang type."); + } + } + else + { + // Neither 'Integral' nor 'Floating Point'. If flow reaches here + // then check type_flags. This type_flags is not a valid type. + error.SetErrorString ("Invalid clang type"); + } + } + else + { + /* 'Complex Floating Point', 'Packed', 'Decimal Floating Point' and 'Aggregate' data types + are yet to be implemented */ + error.SetErrorString ("Currently only Integral and Floating Point clang types are supported."); + } + if(!register_write_successful) + error.SetErrorString ("Register writing failed"); return error; } |

