diff options
| author | Ashok Thirumurthi <ashok.thirumurthi@intel.com> | 2013-04-25 20:12:45 +0000 |
|---|---|---|
| committer | Ashok Thirumurthi <ashok.thirumurthi@intel.com> | 2013-04-25 20:12:45 +0000 |
| commit | 999caf900ae84f666eea7ab5813fb1f446a91651 (patch) | |
| tree | 3a6ad8945ed4e7be619c5b64c6877ce94584f8a0 /lldb/source/Plugins/Process | |
| parent | 3626b7e451016c72668e278cc4f751b0b91975e2 (diff) | |
| download | bcm5719-llvm-999caf900ae84f666eea7ab5813fb1f446a91651.tar.gz bcm5719-llvm-999caf900ae84f666eea7ab5813fb1f446a91651.zip | |
Adds 64-bit POSIX support for AVX
- Adds unique enums for ymm registers to the ABI and the POSIX register context.
- Reworks the register context data structures to support a union of FXSAVE and XSAVE
--- Allows the same code base to deal with the FPU independent of the availability of AVX.
- Determine if AVX is supported by attempting to read XSAVE using ptrace.
--- Support an extended register set for avx registers if available.
- Provide a mechanism to assemble/parse register halves into a single ymm buffer for use with RegisterValue.
--- Reworked Read/WriteRegister routines to read/write/parse ymm registers.
Adds tests for ymm register write with read-back, and expressions involving ymm registers.
- Tests vary depending on the availability of an avx register set.
Thanks to Daniel and Matt for their reviews.
llvm-svn: 180572
Diffstat (limited to 'lldb/source/Plugins/Process')
3 files changed, 399 insertions, 71 deletions
diff --git a/lldb/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h b/lldb/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h index e698892b1cd..d392581c286 100644 --- a/lldb/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h +++ b/lldb/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h @@ -10,6 +10,10 @@ #ifndef liblldb_RegisterContextLinux_x86_64_H_ #define liblldb_RegisterContextLinux_x86_64_H_ +// Architecture specific register sets are described by the ELF core file format +// for use with core dumps and PTRACE extensions like PTRACE_GETREGSET +#include <linux/elf.h> + typedef struct _GPR { uint64_t r15; diff --git a/lldb/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp b/lldb/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp index d26fd5e5ea7..e7d68441004 100644 --- a/lldb/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp +++ b/lldb/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp @@ -66,7 +66,7 @@ enum gpr_esp, gpr_eip, gpr_eflags, - k_last_gpr = gpr_eflags, + k_last_gpr = gpr_eflags, // eRegisterKindLLDB == 33 k_first_fpr, fpu_fcw = k_first_fpr, @@ -104,9 +104,6 @@ enum fpu_xmm14, fpu_xmm15, k_last_fpr = fpu_xmm15, - - k_num_registers, // TODO: Add support for AVX registers - k_first_avx, fpu_ymm0 = k_first_avx, fpu_ymm1, @@ -126,8 +123,9 @@ enum fpu_ymm15, k_last_avx = fpu_ymm15, + k_num_registers, k_num_gpr_registers = k_last_gpr - k_first_gpr + 1, - k_num_fpu_registers = k_last_fpr - k_first_fpr + 1, + k_num_fpr_registers = k_last_fpr - k_first_fpr + 1, k_num_avx_registers = k_last_avx - k_first_avx + 1 }; @@ -173,7 +171,23 @@ enum gcc_dwarf_fpu_stmm4, gcc_dwarf_fpu_stmm5, gcc_dwarf_fpu_stmm6, - gcc_dwarf_fpu_stmm7 + gcc_dwarf_fpu_stmm7, + gcc_dwarf_fpu_ymm0, + gcc_dwarf_fpu_ymm1, + gcc_dwarf_fpu_ymm2, + gcc_dwarf_fpu_ymm3, + gcc_dwarf_fpu_ymm4, + gcc_dwarf_fpu_ymm5, + gcc_dwarf_fpu_ymm6, + gcc_dwarf_fpu_ymm7, + gcc_dwarf_fpu_ymm8, + gcc_dwarf_fpu_ymm9, + gcc_dwarf_fpu_ymm10, + gcc_dwarf_fpu_ymm11, + gcc_dwarf_fpu_ymm12, + gcc_dwarf_fpu_ymm13, + gcc_dwarf_fpu_ymm14, + gcc_dwarf_fpu_ymm15 }; enum @@ -234,7 +248,23 @@ enum gdb_fpu_xmm13 = 53, gdb_fpu_xmm14 = 54, gdb_fpu_xmm15 = 55, - gdb_fpu_mxcsr = 56 + gdb_fpu_mxcsr = 56, + gdb_fpu_ymm0 = 57, + gdb_fpu_ymm1 = 58, + gdb_fpu_ymm2 = 59, + gdb_fpu_ymm3 = 60, + gdb_fpu_ymm4 = 61, + gdb_fpu_ymm5 = 62, + gdb_fpu_ymm6 = 63, + gdb_fpu_ymm7 = 64, + gdb_fpu_ymm8 = 65, + gdb_fpu_ymm9 = 66, + gdb_fpu_ymm10 = 67, + gdb_fpu_ymm11 = 68, + gdb_fpu_ymm12 = 69, + gdb_fpu_ymm13 = 70, + gdb_fpu_ymm14 = 71, + gdb_fpu_ymm15 = 72 }; static const @@ -277,7 +307,7 @@ uint32_t g_gpr_regnums[k_num_gpr_registers] = }; static const uint32_t -g_fpu_regnums[k_num_fpu_registers] = +g_fpu_regnums[k_num_fpr_registers] = { fpu_fcw, fpu_fsw, @@ -347,7 +377,7 @@ static const RegisterSet g_reg_sets[k_num_register_sets] = { { "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums }, - { "Floating Point Registers", "fpu", k_num_fpu_registers, g_fpu_regnums }, + { "Floating Point Registers", "fpu", k_num_fpr_registers, g_fpu_regnums }, { "Advanced Vector Extensions", "avx", k_num_avx_registers, g_avx_regnums } }; @@ -359,7 +389,14 @@ g_reg_sets[k_num_register_sets] = // Computes the offset of the given FPR in the user data area. #define FPR_OFFSET(regname) \ (offsetof(RegisterContext_x86_64::UserArea, i387) + \ - offsetof(RegisterContext_x86_64::FPU, regname)) + offsetof(RegisterContext_x86_64::FPR, xstate) + \ + offsetof(RegisterContext_x86_64::FXSAVE, regname)) + +// Computes the offset of the given YMM register in the user data area. +#define YMM_OFFSET(regname) \ + (offsetof(RegisterContext_x86_64::UserArea, i387) + \ + offsetof(RegisterContext_x86_64::FPR, ymm_set) + \ + offsetof(RegisterContext_x86_64::YMM, regname)) // Number of bytes needed to represent a GPR. #define GPR_SIZE(reg) sizeof(((GPR*)NULL)->reg) @@ -368,7 +405,7 @@ g_reg_sets[k_num_register_sets] = #define GPR_i386_SIZE(reg) sizeof(((RegisterContext_i386::GPR*)NULL)->reg) // Number of bytes needed to represent a FPR. -#define FPR_SIZE(reg) sizeof(((RegisterContext_x86_64::FPU*)NULL)->reg) +#define FPR_SIZE(reg) sizeof(((RegisterContext_x86_64::FXSAVE*)NULL)->reg) // Number of bytes needed to represent the i'th FP register. #define FP_SIZE sizeof(((RegisterContext_x86_64::MMSReg*)NULL)->bytes) @@ -376,6 +413,9 @@ g_reg_sets[k_num_register_sets] = // Number of bytes needed to represent an XMM register. #define XMM_SIZE sizeof(RegisterContext_x86_64::XMMReg) +// Number of bytes needed to represent a YMM register. +#define YMM_SIZE sizeof(RegisterContext_x86_64::YMMReg) + #define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \ { #reg, alt, GPR_SIZE(reg), GPR_OFFSET(reg), eEncodingUint, \ eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg }, NULL, NULL } @@ -400,7 +440,13 @@ g_reg_sets[k_num_register_sets] = { gcc_dwarf_fpu_##reg##i, gcc_dwarf_fpu_##reg##i, \ LLDB_INVALID_REGNUM, gdb_fpu_##reg##i, fpu_##reg##i }, NULL, NULL } -#define REG_CONTEXT_SIZE (sizeof(GPR) + sizeof(RegisterContext_x86_64::FPU)) +#define DEFINE_YMM(reg, i) \ + { #reg#i, NULL, YMM_SIZE, YMM_OFFSET(reg[i]), eEncodingVector, \ + eFormatVectorOfUInt8, \ + { gcc_dwarf_fpu_##reg##i, gcc_dwarf_fpu_##reg##i, \ + LLDB_INVALID_REGNUM, gdb_fpu_##reg##i, fpu_##reg##i }, NULL, NULL } + +#define REG_CONTEXT_SIZE (sizeof(GPR) + sizeof(RegisterContext_x86_64::FPR)) static RegisterInfo g_register_infos[k_num_registers] = @@ -481,7 +527,25 @@ g_register_infos[k_num_registers] = DEFINE_XMM(xmm, 12), DEFINE_XMM(xmm, 13), DEFINE_XMM(xmm, 14), - DEFINE_XMM(xmm, 15) + DEFINE_XMM(xmm, 15), + + // Copy of YMM registers assembled from xmm and ymmh + DEFINE_YMM(ymm, 0), + DEFINE_YMM(ymm, 1), + DEFINE_YMM(ymm, 2), + DEFINE_YMM(ymm, 3), + DEFINE_YMM(ymm, 4), + DEFINE_YMM(ymm, 5), + DEFINE_YMM(ymm, 6), + DEFINE_YMM(ymm, 7), + DEFINE_YMM(ymm, 8), + DEFINE_YMM(ymm, 9), + DEFINE_YMM(ymm, 10), + DEFINE_YMM(ymm, 11), + DEFINE_YMM(ymm, 12), + DEFINE_YMM(ymm, 13), + DEFINE_YMM(ymm, 14), + DEFINE_YMM(ymm, 15) }; static unsigned GetRegOffset(unsigned reg) @@ -501,20 +565,41 @@ static bool IsGPR(unsigned reg) return reg <= k_last_gpr; // GPR's come first. } +static bool IsAVX(unsigned reg) +{ + return (k_first_avx <= reg && reg <= k_last_avx); +} static bool IsFPR(unsigned reg) { return (k_first_fpr <= reg && reg <= k_last_fpr); } -static bool IsAVX(unsigned reg) + +bool RegisterContext_x86_64::IsFPR(unsigned reg, FPRType fpr_type) { - return (k_first_avx <= reg && reg <= k_last_avx); + bool generic_fpr = ::IsFPR(reg); + if (fpr_type == eXSAVE) + return generic_fpr || IsAVX(reg); + + return generic_fpr; } RegisterContext_x86_64::RegisterContext_x86_64(Thread &thread, uint32_t concrete_frame_idx) : RegisterContextPOSIX(thread, concrete_frame_idx) { + // Initialize user.iovec to point to the buffer and buffer size + // using the conventions of Berkeley style UIO structures, as required + // by PTRACE extensions. + user.iovec.iov_base = &user.i387.xstate.xsave; + user.iovec.iov_len = sizeof(user.i387.xstate.xsave); + + ::memset(&user.i387, 0, sizeof(RegisterContext_x86_64::FPR)); + + // TODO: Use assembly to call cpuid on the inferior and query ebx or ecx + user.fpr_type = eXSAVE; // extended floating-point registers, if available + if (false == ReadFPR()) + user.fpr_type = eFXSAVE; // assume generic floating-point registers } RegisterContext_x86_64::~RegisterContext_x86_64() @@ -542,7 +627,10 @@ RegisterContext_x86_64::InvalidateAllRegisters() size_t RegisterContext_x86_64::GetRegisterCount() { - return k_num_registers; + size_t num_registers = k_num_gpr_registers + k_num_fpr_registers; + if (user.fpr_type == eXSAVE) + return num_registers + k_num_avx_registers; + return num_registers; } const RegisterInfo * @@ -594,11 +682,82 @@ RegisterContext_x86_64::GetRegisterName(unsigned reg) return g_register_infos[reg].name; } +lldb::ByteOrder +RegisterContext_x86_64::GetByteOrder() +{ + // Get the target process whose privileged thread was used for the register read. + lldb::ByteOrder byte_order = eByteOrderInvalid; + Process *process = CalculateProcess().get(); + + if (process) + byte_order = process->GetByteOrder(); + return byte_order; +} + +// Parse ymm registers and into xmm.bytes and ymmh.bytes. +bool CopyYMMtoXSTATE(uint32_t reg, RegisterContext_x86_64::UserArea &user, lldb::ByteOrder byte_order) +{ + if (!IsAVX(reg)) + return false; + + if (byte_order == eByteOrderLittle) { + ::memcpy(user.i387.xstate.fxsave.xmm[reg - fpu_ymm0].bytes, + user.i387.ymm_set.ymm[reg - fpu_ymm0].bytes, + sizeof(RegisterContext_x86_64::XMMReg)); + ::memcpy(user.i387.xstate.xsave.ymmh[reg - fpu_ymm0].bytes, + user.i387.ymm_set.ymm[reg - fpu_ymm0].bytes + sizeof(RegisterContext_x86_64::XMMReg), + sizeof(RegisterContext_x86_64::YMMHReg)); + return true; + } + + if (byte_order == eByteOrderBig) { + ::memcpy(user.i387.xstate.fxsave.xmm[reg - fpu_ymm0].bytes, + user.i387.ymm_set.ymm[reg - fpu_ymm0].bytes + sizeof(RegisterContext_x86_64::XMMReg), + sizeof(RegisterContext_x86_64::XMMReg)); + ::memcpy(user.i387.xstate.xsave.ymmh[reg - fpu_ymm0].bytes, + user.i387.ymm_set.ymm[reg - fpu_ymm0].bytes, + sizeof(RegisterContext_x86_64::YMMHReg)); + return true; + } + return false; // unsupported or invalid byte order +} + +// Concatenate xmm.bytes with ymmh.bytes +bool CopyXSTATEtoYMM(uint32_t reg, RegisterContext_x86_64::UserArea &user, lldb::ByteOrder byte_order) +{ + if (!IsAVX(reg)) + return false; + + if (byte_order == eByteOrderLittle) { + ::memcpy(user.i387.ymm_set.ymm[reg - fpu_ymm0].bytes, + user.i387.xstate.fxsave.xmm[reg - fpu_ymm0].bytes, + sizeof(RegisterContext_x86_64::XMMReg)); + ::memcpy(user.i387.ymm_set.ymm[reg - fpu_ymm0].bytes + sizeof(RegisterContext_x86_64::XMMReg), + user.i387.xstate.xsave.ymmh[reg - fpu_ymm0].bytes, + sizeof(RegisterContext_x86_64::YMMHReg)); + return true; + } + if (byte_order == eByteOrderBig) { + ::memcpy(user.i387.ymm_set.ymm[reg - fpu_ymm0].bytes + sizeof(RegisterContext_x86_64::XMMReg), + user.i387.xstate.fxsave.xmm[reg - fpu_ymm0].bytes, + sizeof(RegisterContext_x86_64::XMMReg)); + ::memcpy(user.i387.ymm_set.ymm[reg - fpu_ymm0].bytes, + user.i387.xstate.xsave.ymmh[reg - fpu_ymm0].bytes, + sizeof(RegisterContext_x86_64::YMMHReg)); + return true; + } + return false; // unsupported or invalid byte order +} + bool RegisterContext_x86_64::IsRegisterSetAvailable(size_t set_index) { - // Note: Extended register sets are assumed to be at the end of g_reg_sets. - return (set_index < k_num_register_sets - k_num_extended_register_sets); + // Note: Extended register sets are assumed to be at the end of g_reg_sets... + size_t num_sets = k_num_register_sets - k_num_extended_register_sets; + if (user.fpr_type == eXSAVE) // ...and to start with AVX registers. + ++num_sets; + + return (set_index < num_sets); } bool @@ -606,10 +765,7 @@ RegisterContext_x86_64::ReadRegister(const RegisterInfo *reg_info, RegisterValue { const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - if (IsAVX(reg)) - return false; - - if (IsFPR(reg)) { + if (IsFPR(reg, user.fpr_type)) { if (!ReadFPR()) return false; } @@ -619,17 +775,23 @@ RegisterContext_x86_64::ReadRegister(const RegisterInfo *reg_info, RegisterValue } if (reg_info->encoding == eEncodingVector) { - // Get the target process whose privileged thread was used for the register read. - Process *process = CalculateProcess().get(); - if (process) { + ByteOrder byte_order = GetByteOrder(); + + if (byte_order != ByteOrder::eByteOrderInvalid) { if (reg >= fpu_stmm0 && reg <= fpu_stmm7) { - value.SetBytes(user.i387.stmm[reg - fpu_stmm0].bytes, reg_info->byte_size, process->GetByteOrder()); - return value.GetType() == RegisterValue::eTypeBytes; + value.SetBytes(user.i387.xstate.fxsave.stmm[reg - fpu_stmm0].bytes, reg_info->byte_size, byte_order); } if (reg >= fpu_xmm0 && reg <= fpu_xmm15) { - value.SetBytes(user.i387.xmm[reg - fpu_xmm0].bytes, reg_info->byte_size, process->GetByteOrder()); - return value.GetType() == RegisterValue::eTypeBytes; + value.SetBytes(user.i387.xstate.fxsave.xmm[reg - fpu_xmm0].bytes, reg_info->byte_size, byte_order); } + if (reg >= fpu_ymm0 && reg <= fpu_ymm15) { + // Concatenate ymm using the register halves in xmm.bytes and ymmh.bytes + if (user.fpr_type == eXSAVE && CopyXSTATEtoYMM(reg, user, byte_order)) + value.SetBytes(user.i387.ymm_set.ymm[reg - fpu_ymm0].bytes, reg_info->byte_size, byte_order); + else + return false; + } + return value.GetType() == RegisterValue::eTypeBytes; } return false; } @@ -640,28 +802,28 @@ RegisterContext_x86_64::ReadRegister(const RegisterInfo *reg_info, RegisterValue default: return false; case fpu_dp: - value = user.i387.dp; + value = user.i387.xstate.fxsave.dp; break; case fpu_fcw: - value = user.i387.fcw; + value = user.i387.xstate.fxsave.fcw; break; case fpu_fsw: - value = user.i387.fsw; + value = user.i387.xstate.fxsave.fsw; break; case fpu_ip: - value = user.i387.ip; + value = user.i387.xstate.fxsave.ip; break; case fpu_fop: - value = user.i387.fop; + value = user.i387.xstate.fxsave.fop; break; case fpu_ftw: - value = user.i387.ftw; + value = user.i387.xstate.fxsave.ftw; break; case fpu_mxcsr: - value = user.i387.mxcsr; + value = user.i387.xstate.fxsave.mxcsr; break; case fpu_mxcsrmask: - value = user.i387.mxcsrmask; + value = user.i387.xstate.fxsave.mxcsrmask; break; } return true; @@ -670,22 +832,39 @@ RegisterContext_x86_64::ReadRegister(const RegisterInfo *reg_info, RegisterValue bool RegisterContext_x86_64::ReadAllRegisterValues(DataBufferSP &data_sp) { + bool success = false; data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); if (data_sp && ReadGPR () && ReadFPR ()) { uint8_t *dst = data_sp->GetBytes(); - ::memcpy (dst, &user.regs, sizeof(user.regs)); - dst += sizeof(user.regs); + success = dst != 0; - ::memcpy (dst, &user.i387, sizeof(user.i387)); - return true; + if (success) { + ::memcpy (dst, &user.regs, sizeof(user.regs)); + dst += sizeof(user.regs); + } + if (user.fpr_type == eFXSAVE) + ::memcpy (dst, &user.i387.xstate.fxsave, sizeof(user.i387.xstate.fxsave)); + + if (user.fpr_type == eXSAVE) { + ByteOrder byte_order = GetByteOrder(); + + // Assemble the YMM register content from the register halves. + for (uint32_t reg = fpu_ymm0; success && reg <= fpu_ymm15; ++reg) + success = CopyXSTATEtoYMM(reg, user, byte_order); + + if (success) { + // Copy the extended register state including the assembled ymm registers. + ::memcpy (dst, &user.i387, sizeof(user.i387)); + } + } } - return false; + return success; } bool RegisterContext_x86_64::WriteRegister(const lldb_private::RegisterInfo *reg_info, - const lldb_private::RegisterValue &value) + const lldb_private::RegisterValue &value) { const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; if (IsGPR(reg)) { @@ -693,8 +872,7 @@ RegisterContext_x86_64::WriteRegister(const lldb_private::RegisterInfo *reg_info return monitor.WriteRegisterValue(m_thread.GetID(), GetRegOffset(reg), value); } - if (IsFPR(reg)) { - // Note that lldb uses slightly different naming conventions from sys/user.h + if (IsFPR(reg, user.fpr_type)) { switch (reg) { default: @@ -702,37 +880,49 @@ RegisterContext_x86_64::WriteRegister(const lldb_private::RegisterInfo *reg_info return false; if (reg >= fpu_stmm0 && reg <= fpu_stmm7) - ::memcpy (user.i387.stmm[reg - fpu_stmm0].bytes, value.GetBytes(), value.GetByteSize()); + ::memcpy (user.i387.xstate.fxsave.stmm[reg - fpu_stmm0].bytes, value.GetBytes(), value.GetByteSize()); if (reg >= fpu_xmm0 && reg <= fpu_xmm15) - ::memcpy (user.i387.xmm[reg - fpu_xmm0].bytes, value.GetBytes(), value.GetByteSize()); + ::memcpy (user.i387.xstate.fxsave.xmm[reg - fpu_xmm0].bytes, value.GetBytes(), value.GetByteSize()); + + if (reg >= fpu_ymm0 && reg <= fpu_ymm15) { + if (user.fpr_type != eXSAVE) + return false; // the target processor does not support AVX + + // Store ymm register content, and split into the register halves in xmm.bytes and ymmh.bytes + ::memcpy (user.i387.ymm_set.ymm[reg - fpu_ymm0].bytes, value.GetBytes(), value.GetByteSize()); + if (false == CopyYMMtoXSTATE(reg, user, GetByteOrder())) + return false; + } break; case fpu_dp: - user.i387.dp = value.GetAsUInt64(); + user.i387.xstate.fxsave.dp = value.GetAsUInt64(); break; case fpu_fcw: - user.i387.fcw = value.GetAsUInt16(); + user.i387.xstate.fxsave.fcw = value.GetAsUInt16(); break; case fpu_fsw: - user.i387.fsw = value.GetAsUInt16(); + user.i387.xstate.fxsave.fsw = value.GetAsUInt16(); break; case fpu_ip: - user.i387.ip = value.GetAsUInt64(); + user.i387.xstate.fxsave.ip = value.GetAsUInt64(); break; case fpu_fop: - user.i387.fop = value.GetAsUInt16(); + user.i387.xstate.fxsave.fop = value.GetAsUInt16(); break; case fpu_ftw: - user.i387.ftw = value.GetAsUInt16(); + user.i387.xstate.fxsave.ftw = value.GetAsUInt16(); break; case fpu_mxcsr: - user.i387.mxcsr = value.GetAsUInt32(); + user.i387.xstate.fxsave.mxcsr = value.GetAsUInt32(); break; case fpu_mxcsrmask: - user.i387.mxcsrmask = value.GetAsUInt32(); + user.i387.xstate.fxsave.mxcsrmask = value.GetAsUInt32(); break; } if (WriteFPR()) { + if (IsAVX(reg)) + return CopyYMMtoXSTATE(reg, user, GetByteOrder()); return true; } } @@ -742,16 +932,36 @@ RegisterContext_x86_64::WriteRegister(const lldb_private::RegisterInfo *reg_info bool RegisterContext_x86_64::WriteAllRegisterValues(const DataBufferSP &data_sp) { + bool success = false; if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) { - const uint8_t *src = data_sp->GetBytes(); - ::memcpy (&user.regs, src, sizeof(user.regs)); - src += sizeof(user.regs); - - ::memcpy (&user.i387, src, sizeof(user.i387)); - return WriteGPR() & WriteFPR(); + uint8_t *src = data_sp->GetBytes(); + if (src) { + ::memcpy (&user.regs, src, sizeof(user.regs)); + + if (WriteGPR()) { + src += sizeof(user.regs); + if (user.fpr_type == eFXSAVE) + ::memcpy (&user.i387.xstate.fxsave, src, sizeof(user.i387.xstate.fxsave)); + if (user.fpr_type == eXSAVE) + ::memcpy (&user.i387.xstate.xsave, src, sizeof(user.i387.xstate.xsave)); + + success = WriteFPR(); + if (success) { + success = true; + + if (user.fpr_type == eXSAVE) { + ByteOrder byte_order = GetByteOrder(); + + // Parse the YMM register content from the register halves. + for (uint32_t reg = fpu_ymm0; success && reg <= fpu_ymm15; ++reg) + success = CopyYMMtoXSTATE(reg, user, byte_order); + } + } + } + } } - return false; + return success; } bool @@ -951,6 +1161,22 @@ RegisterContext_x86_64::ConvertRegisterKindToRegisterNumber(uint32_t kind, case gcc_dwarf_fpu_stmm5: return fpu_stmm5; case gcc_dwarf_fpu_stmm6: return fpu_stmm6; case gcc_dwarf_fpu_stmm7: return fpu_stmm7; + case gcc_dwarf_fpu_ymm0: return fpu_ymm0; + case gcc_dwarf_fpu_ymm1: return fpu_ymm1; + case gcc_dwarf_fpu_ymm2: return fpu_ymm2; + case gcc_dwarf_fpu_ymm3: return fpu_ymm3; + case gcc_dwarf_fpu_ymm4: return fpu_ymm4; + case gcc_dwarf_fpu_ymm5: return fpu_ymm5; + case gcc_dwarf_fpu_ymm6: return fpu_ymm6; + case gcc_dwarf_fpu_ymm7: return fpu_ymm7; + case gcc_dwarf_fpu_ymm8: return fpu_ymm8; + case gcc_dwarf_fpu_ymm9: return fpu_ymm9; + case gcc_dwarf_fpu_ymm10: return fpu_ymm10; + case gcc_dwarf_fpu_ymm11: return fpu_ymm11; + case gcc_dwarf_fpu_ymm12: return fpu_ymm12; + case gcc_dwarf_fpu_ymm13: return fpu_ymm13; + case gcc_dwarf_fpu_ymm14: return fpu_ymm14; + case gcc_dwarf_fpu_ymm15: return fpu_ymm15; default: return LLDB_INVALID_REGNUM; } @@ -1017,6 +1243,22 @@ RegisterContext_x86_64::ConvertRegisterKindToRegisterNumber(uint32_t kind, case gdb_fpu_xmm14 : return fpu_xmm14; case gdb_fpu_xmm15 : return fpu_xmm15; case gdb_fpu_mxcsr : return fpu_mxcsr; + case gdb_fpu_ymm0 : return fpu_ymm0; + case gdb_fpu_ymm1 : return fpu_ymm1; + case gdb_fpu_ymm2 : return fpu_ymm2; + case gdb_fpu_ymm3 : return fpu_ymm3; + case gdb_fpu_ymm4 : return fpu_ymm4; + case gdb_fpu_ymm5 : return fpu_ymm5; + case gdb_fpu_ymm6 : return fpu_ymm6; + case gdb_fpu_ymm7 : return fpu_ymm7; + case gdb_fpu_ymm8 : return fpu_ymm8; + case gdb_fpu_ymm9 : return fpu_ymm9; + case gdb_fpu_ymm10 : return fpu_ymm10; + case gdb_fpu_ymm11 : return fpu_ymm11; + case gdb_fpu_ymm12 : return fpu_ymm12; + case gdb_fpu_ymm13 : return fpu_ymm13; + case gdb_fpu_ymm14 : return fpu_ymm14; + case gdb_fpu_ymm15 : return fpu_ymm15; default: return LLDB_INVALID_REGNUM; } @@ -1070,19 +1312,30 @@ bool RegisterContext_x86_64::ReadFPR() { ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadFPR(m_thread.GetID(), &user.i387, sizeof(user.i387)); + if (user.fpr_type == eFXSAVE) + return monitor.ReadFPR(m_thread.GetID(), &user.i387.xstate.fxsave, sizeof(user.i387.xstate.fxsave)); + + if (user.fpr_type == eXSAVE) + return monitor.ReadRegisterSet(m_thread.GetID(), &user.iovec, sizeof(user.i387.xstate.xsave), NT_X86_XSTATE); + return false; } bool RegisterContext_x86_64::WriteGPR() { - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteGPR(m_thread.GetID(), &user.regs, sizeof(user.regs)); + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteGPR(m_thread.GetID(), &user.regs, sizeof(user.regs)); } bool RegisterContext_x86_64::WriteFPR() { ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteFPR(m_thread.GetID(), &user.i387, sizeof(user.i387)); + if (user.fpr_type == eFXSAVE) + return monitor.WriteFPR(m_thread.GetID(), &user.i387.xstate.fxsave, sizeof(user.i387.xstate.fxsave)); + + if (user.fpr_type == eXSAVE) + return monitor.WriteRegisterSet(m_thread.GetID(), &user.iovec, sizeof(user.i387.xstate.xsave), NT_X86_XSTATE); + return false; } + diff --git a/lldb/source/Plugins/Process/POSIX/RegisterContext_x86_64.h b/lldb/source/Plugins/Process/POSIX/RegisterContext_x86_64.h index ac9bfdf186a..169ebe00e84 100644 --- a/lldb/source/Plugins/Process/POSIX/RegisterContext_x86_64.h +++ b/lldb/source/Plugins/Process/POSIX/RegisterContext_x86_64.h @@ -79,6 +79,9 @@ public: bool UpdateAfterBreakpoint(); + //--------------------------------------------------------------------------- + // Generic floating-point registers + //--------------------------------------------------------------------------- struct MMSReg { uint8_t bytes[10]; @@ -87,10 +90,10 @@ public: struct XMMReg { - uint8_t bytes[16]; + uint8_t bytes[16]; // 128-bits for each XMM register }; - struct FPU + struct FXSAVE { uint16_t fcw; uint16_t fsw; @@ -105,12 +108,76 @@ public: uint32_t padding[24]; }; + //--------------------------------------------------------------------------- + // Extended floating-point registers + //--------------------------------------------------------------------------- + struct YMMHReg + { + uint8_t bytes[16]; // 16 * 8 bits for the high bytes of each YMM register + }; + + struct YMMReg + { + uint8_t bytes[32]; // 16 * 16 bits for each YMM register + }; + + struct YMM + { + YMMReg ymm[16]; // assembled from ymmh and xmm registers + }; + + struct XSAVE_HDR + { + uint64_t xstate_bv; // OS enabled xstate mask to determine the extended states supported by the processor + uint64_t reserved1[2]; + uint64_t reserved2[5]; + } __attribute__((packed)); + + // x86 extensions to FXSAVE (i.e. for AVX processors) + struct XSAVE + { + FXSAVE i387; // floating point registers typical in i387_fxsave_struct + XSAVE_HDR header; // The xsave_hdr_struct can be used to determine if the following extensions are usable + YMMHReg ymmh[16]; // High 16 bytes of each of 16 YMM registers (the low bytes are in FXSAVE.xmm for compatibility with SSE) + // Slot any extensions to the register file here + } __attribute__((packed, aligned (64))); + + struct IOVEC + { + void *iov_base; // pointer to XSAVE + size_t iov_len; // sizeof(XSAVE) + }; + + //--------------------------------------------------------------------------- + // Note: prefer kernel definitions over user-land + //--------------------------------------------------------------------------- + enum FPRType + { + eNotValid = 0, + eFSAVE, // TODO + eFXSAVE, + eSOFT, // TODO + eXSAVE + }; + + // Floating-point registers + struct FPR + { + // Thread state for the floating-point unit of the processor read by ptrace. + union XSTATE { + FXSAVE fxsave; // Generic floating-point registers. + XSAVE xsave; // x86 extended processor state. + } xstate; + + YMM ymm_set; // Copy of ymmh and xmm register halves. + }; + struct UserArea { GPR regs; // General purpose registers. - int32_t fpvalid; // True if FPU is being used. + FPRType fpr_type; // Determines the type of data stored by union FPR, if any. int32_t pad0; - FPU i387; // FPU registers. + FPR i387; // Floating point registers. uint64_t tsize; // Text segment size. uint64_t dsize; // Data segment size. uint64_t ssize; // Stack segment size. @@ -120,12 +187,13 @@ public: int32_t reserved; // Unused. int32_t pad1; uint64_t ar0; // Location of GPR's. - FPU* fpstate; // Location of FPR's. + FPR* fpstate; // Location of FPR's. uint64_t magic; // Identifier for core dumps. char u_comm[32]; // Command causing core dump. uint64_t u_debugreg[8]; // Debug registers (DR0 - DR7). uint64_t error_code; // CPU error code. uint64_t fault_address; // Control register CR3. + IOVEC iovec; // wrapper for xsave }; protected: @@ -137,6 +205,9 @@ private: UserArea user; ProcessMonitor &GetMonitor(); + lldb::ByteOrder GetByteOrder(); + + static bool IsFPR(unsigned reg, FPRType fpr_type); bool ReadGPR(); bool ReadFPR(); |

