summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Process
diff options
context:
space:
mode:
authorAshok Thirumurthi <ashok.thirumurthi@intel.com>2013-04-25 20:12:45 +0000
committerAshok Thirumurthi <ashok.thirumurthi@intel.com>2013-04-25 20:12:45 +0000
commit999caf900ae84f666eea7ab5813fb1f446a91651 (patch)
tree3a6ad8945ed4e7be619c5b64c6877ce94584f8a0 /lldb/source/Plugins/Process
parent3626b7e451016c72668e278cc4f751b0b91975e2 (diff)
downloadbcm5719-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')
-rw-r--r--lldb/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h4
-rw-r--r--lldb/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp385
-rw-r--r--lldb/source/Plugins/Process/POSIX/RegisterContext_x86_64.h81
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();
OpenPOWER on IntegriCloud