mgorny created this revision.
mgorny added reviewers: labath, emaste, krytarowski.
mgorny requested review of this revision.
Add a framework for reading/writing extended register sets via
PT_GETXSTATE/PT_GETXSTATE_INFO/PT_SETXSTATE, and use it to support
YMM0..YMM15. The code is prepared to handle arbitrary XSAVE extensions,
including correct offset handling.
https://reviews.llvm.org/D89193
Files:
lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_x86_64.cpp
lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_x86_64.h
Index: lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_x86_64.h
===================================================================
--- lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_x86_64.h
+++ lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_x86_64.h
@@ -22,6 +22,8 @@
#include "Plugins/Process/Utility/RegisterContext_x86.h"
#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
+#define LLDB_INVALID_XSAVE_OFFSET UINT32_MAX
+
namespace lldb_private {
namespace process_freebsd {
@@ -75,7 +77,11 @@
private:
// Private member types.
- enum { GPRegSet, FPRegSet, DBRegSet };
+ enum { GPRegSet, FPRegSet, XSaveRegSet, DBRegSet };
+ enum {
+ YMMXSaveSet,
+ MaxXSaveSet = YMMXSaveSet,
+ };
// Private member variables.
struct reg m_gpr;
@@ -85,6 +91,8 @@
struct xmmreg m_fpr;
#endif
struct dbreg m_dbr;
+ std::vector<uint8_t> m_xsave;
+ std::array<uint32_t, MaxXSaveSet + 1> m_xsave_offsets;
int GetSetForNativeRegNum(int reg_num) const;
int GetDR(int num) const;
Index: lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_x86_64.cpp
===================================================================
--- lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_x86_64.cpp
+++ lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_x86_64.cpp
@@ -10,7 +10,11 @@
#include "NativeRegisterContextFreeBSD_x86_64.h"
+// clang-format off
#include <machine/fpu.h>
+#include <x86/specialreg.h>
+#include <cpuid.h>
+// clang-format on
#include "lldb/Host/HostInfo.h"
#include "lldb/Utility/DataBufferHeap.h"
@@ -18,6 +22,7 @@
#include "lldb/Utility/RegisterValue.h"
#include "lldb/Utility/Status.h"
+#include "NativeProcessFreeBSD.h"
#include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h"
#include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h"
@@ -392,7 +397,7 @@
if (reg_num >= k_first_fpr_i386 && reg_num <= k_last_fpr_i386)
return FPRegSet;
if (reg_num >= k_first_avx_i386 && reg_num <= k_last_avx_i386)
- return -1; // AVX
+ return XSaveRegSet; // AVX
if (reg_num >= k_first_mpxr_i386 && reg_num <= k_last_mpxr_i386)
return -1; // MPXR
if (reg_num >= k_first_mpxc_i386 && reg_num <= k_last_mpxc_i386)
@@ -406,7 +411,7 @@
if (reg_num >= k_first_fpr_x86_64 && reg_num <= k_last_fpr_x86_64)
return FPRegSet;
if (reg_num >= k_first_avx_x86_64 && reg_num <= k_last_avx_x86_64)
- return -1; // AVX
+ return XSaveRegSet; // AVX
if (reg_num >= k_first_mpxr_x86_64 && reg_num <= k_last_mpxr_x86_64)
return -1; // MPXR
if (reg_num >= k_first_mpxc_x86_64 && reg_num <= k_last_mpxc_x86_64)
@@ -433,6 +438,27 @@
#endif
case DBRegSet:
return DoRegisterSet(PT_GETDBREGS, &m_dbr);
+ case XSaveRegSet: {
+ struct ptrace_xstate_info info;
+ Status ret = NativeProcessFreeBSD::PtraceWrapper(
+ PT_GETXSTATE_INFO, GetProcessPid(), &info, sizeof(info));
+ if (!ret.Success())
+ return ret;
+
+ assert(info.xsave_mask & XFEATURE_ENABLED_X87);
+ assert(info.xsave_mask & XFEATURE_ENABLED_SSE);
+
+ m_xsave_offsets[YMMXSaveSet] = LLDB_INVALID_XSAVE_OFFSET;
+ if (info.xsave_mask & XFEATURE_ENABLED_YMM_HI128) {
+ uint32_t eax, ecx, edx;
+ __get_cpuid_count(0x0D, 2, &eax, &m_xsave_offsets[YMMXSaveSet], &ecx,
+ &edx);
+ }
+
+ m_xsave.resize(info.xsave_len);
+ return NativeProcessFreeBSD::PtraceWrapper(PT_GETXSTATE, GetProcessPid(),
+ m_xsave.data(), m_xsave.size());
+ }
}
llvm_unreachable("NativeRegisterContextFreeBSD_x86_64::ReadRegisterSet");
}
@@ -449,6 +475,11 @@
#endif
case DBRegSet:
return DoRegisterSet(PT_SETDBREGS, &m_dbr);
+ case XSaveRegSet:
+ // TODO: can WriteRegisterSet() ever be called without ReadRegisterSet()?
+ assert(m_xsave.size() > 0);
+ return NativeProcessFreeBSD::PtraceWrapper(PT_SETXSTATE, GetProcessPid(),
+ m_xsave.data(), m_xsave.size());
}
llvm_unreachable("NativeRegisterContextFreeBSD_x86_64::WriteRegisterSet");
}
@@ -713,6 +744,39 @@
reg_info->byte_size, endian::InlHostByteOrder());
#endif
break;
+ case lldb_ymm0_x86_64:
+ case lldb_ymm1_x86_64:
+ case lldb_ymm2_x86_64:
+ case lldb_ymm3_x86_64:
+ case lldb_ymm4_x86_64:
+ case lldb_ymm5_x86_64:
+ case lldb_ymm6_x86_64:
+ case lldb_ymm7_x86_64:
+ case lldb_ymm8_x86_64:
+ case lldb_ymm9_x86_64:
+ case lldb_ymm10_x86_64:
+ case lldb_ymm11_x86_64:
+ case lldb_ymm12_x86_64:
+ case lldb_ymm13_x86_64:
+ case lldb_ymm14_x86_64:
+ case lldb_ymm15_x86_64: {
+ uint32_t offset = m_xsave_offsets[YMMXSaveSet];
+ if (offset == LLDB_INVALID_XSAVE_OFFSET) {
+ error.SetErrorStringWithFormat(
+ "register \"%s\" not supported by CPU/kernel", reg_info->name);
+ } else {
+ uint32_t reg_index = reg - lldb_ymm0_x86_64;
+ auto *fpreg = reinterpret_cast<struct savexmm_ymm *>(m_xsave.data());
+ auto *ymmreg = reinterpret_cast<struct ymmacc *>(m_xsave.data() + offset);
+
+ YMMReg ymm =
+ XStateToYMM(reinterpret_cast<void *>(&fpreg->sv_xmm[reg_index]),
+ reinterpret_cast<void *>(&ymmreg[reg_index]));
+ reg_value.SetBytes(ymm.bytes, reg_info->byte_size,
+ endian::InlHostByteOrder());
+ }
+ break;
+ }
case lldb_dr0_x86_64:
case lldb_dr1_x86_64:
case lldb_dr2_x86_64:
@@ -983,6 +1047,38 @@
reg_value.GetByteSize());
#endif
break;
+ case lldb_ymm0_x86_64:
+ case lldb_ymm1_x86_64:
+ case lldb_ymm2_x86_64:
+ case lldb_ymm3_x86_64:
+ case lldb_ymm4_x86_64:
+ case lldb_ymm5_x86_64:
+ case lldb_ymm6_x86_64:
+ case lldb_ymm7_x86_64:
+ case lldb_ymm8_x86_64:
+ case lldb_ymm9_x86_64:
+ case lldb_ymm10_x86_64:
+ case lldb_ymm11_x86_64:
+ case lldb_ymm12_x86_64:
+ case lldb_ymm13_x86_64:
+ case lldb_ymm14_x86_64:
+ case lldb_ymm15_x86_64: {
+ uint32_t offset = m_xsave_offsets[YMMXSaveSet];
+ if (offset == LLDB_INVALID_XSAVE_OFFSET) {
+ error.SetErrorStringWithFormat(
+ "register \"%s\" not supported by CPU/kernel", reg_info->name);
+ } else {
+ uint32_t reg_index = reg - lldb_ymm0_x86_64;
+ auto *fpreg = reinterpret_cast<struct savexmm_ymm *>(m_xsave.data());
+ auto *ymmreg = reinterpret_cast<struct ymmacc *>(m_xsave.data() + offset);
+
+ YMMReg ymm;
+ ::memcpy(ymm.bytes, reg_value.GetBytes(), reg_value.GetByteSize());
+ YMMToXState(ymm, reinterpret_cast<void *>(&fpreg->sv_xmm[reg_index]),
+ reinterpret_cast<void *>(&ymmreg[reg_index]));
+ }
+ break;
+ }
case lldb_dr0_x86_64:
case lldb_dr1_x86_64:
case lldb_dr2_x86_64:
@@ -1028,10 +1124,11 @@
}
if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
- error.SetErrorStringWithFormat(
- "NativeRegisterContextFreeBSD_x86_64::%s data_sp contained mismatched "
- "data size, expected %zu, actual %" PRIu64,
- __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
+ error.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_x86_64::%s "
+ "data_sp contained mismatched "
+ "data size, expected %zu, actual %" PRIu64,
+ __FUNCTION__, REG_CONTEXT_SIZE,
+ data_sp->GetByteSize());
return error;
}
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits