diff --git a/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_x86_64.h b/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_x86_64.h --- a/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_x86_64.h +++ b/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_x86_64.h @@ -70,11 +70,7 @@ // Private member variables. std::array m_gpr; -#if defined(__x86_64__) - struct fpreg m_fpr; -#else - struct xmmreg m_fpr; -#endif + std::array m_fpr; // FXSAVE struct dbreg m_dbr; std::vector m_xsave; std::array m_xsave_offsets; @@ -84,6 +80,8 @@ Status ReadRegisterSet(uint32_t set); Status WriteRegisterSet(uint32_t set); + + size_t GetFPROffset() const; }; } // namespace process_freebsd diff --git a/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_x86_64.cpp b/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_x86_64.cpp --- a/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_x86_64.cpp +++ b/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_x86_64.cpp @@ -248,7 +248,7 @@ const ArchSpec &target_arch, NativeThreadProtocol &native_thread) : NativeRegisterContextRegisterInfo( native_thread, CreateRegisterInfoInterface(target_arch)), - m_fpr(), m_dbr() { + m_dbr() { assert(m_gpr.size() == GetRegisterInfoInterface().GetGPRSize()); } @@ -278,53 +278,6 @@ static constexpr int RegNumX86ToX86_64(int regnum) { switch (regnum) { - case lldb_fctrl_i386: - return lldb_fctrl_x86_64; - case lldb_fstat_i386: - return lldb_fstat_x86_64; - case lldb_ftag_i386: - return lldb_ftag_x86_64; - case lldb_fop_i386: - return lldb_fop_x86_64; - case lldb_fiseg_i386: - return lldb_fiseg_x86_64; - case lldb_fioff_i386: - return lldb_fioff_x86_64; - case lldb_foseg_i386: - return lldb_foseg_x86_64; - case lldb_fooff_i386: - return lldb_fooff_x86_64; - case lldb_mxcsr_i386: - return lldb_mxcsr_x86_64; - case lldb_mxcsrmask_i386: - return lldb_mxcsrmask_x86_64; - case lldb_st0_i386: - case lldb_st1_i386: - case lldb_st2_i386: - case lldb_st3_i386: - case lldb_st4_i386: - case lldb_st5_i386: - case lldb_st6_i386: - case lldb_st7_i386: - return lldb_st0_x86_64 + regnum - lldb_st0_i386; - case lldb_mm0_i386: - case lldb_mm1_i386: - case lldb_mm2_i386: - case lldb_mm3_i386: - case lldb_mm4_i386: - case lldb_mm5_i386: - case lldb_mm6_i386: - case lldb_mm7_i386: - return lldb_mm0_x86_64 + regnum - lldb_mm0_i386; - case lldb_xmm0_i386: - case lldb_xmm1_i386: - case lldb_xmm2_i386: - case lldb_xmm3_i386: - case lldb_xmm4_i386: - case lldb_xmm5_i386: - case lldb_xmm6_i386: - case lldb_xmm7_i386: - return lldb_xmm0_x86_64 + regnum - lldb_xmm0_i386; case lldb_ymm0_i386: case lldb_ymm1_i386: case lldb_ymm2_i386: @@ -403,10 +356,10 @@ case FPRegSet: #if defined(__x86_64__) return NativeProcessFreeBSD::PtraceWrapper(PT_GETFPREGS, m_thread.GetID(), - &m_fpr); + m_fpr.data()); #else return NativeProcessFreeBSD::PtraceWrapper(PT_GETXMMREGS, m_thread.GetID(), - &m_fpr); + m_fpr.data()); #endif case DBRegSet: return NativeProcessFreeBSD::PtraceWrapper(PT_GETDBREGS, m_thread.GetID(), @@ -444,10 +397,10 @@ case FPRegSet: #if defined(__x86_64__) return NativeProcessFreeBSD::PtraceWrapper(PT_SETFPREGS, m_thread.GetID(), - &m_fpr); + m_fpr.data()); #else return NativeProcessFreeBSD::PtraceWrapper(PT_SETXMMREGS, m_thread.GetID(), - &m_fpr); + m_fpr.data()); #endif case DBRegSet: return NativeProcessFreeBSD::PtraceWrapper(PT_SETDBREGS, m_thread.GetID(), @@ -501,6 +454,9 @@ reg_info->byte_size, endian::InlHostByteOrder()); return error; case FPRegSet: + reg_value.SetBytes(m_fpr.data() + reg_info->byte_offset - GetFPROffset(), + reg_info->byte_size, endian::InlHostByteOrder()); + return error; case XSaveRegSet: case DBRegSet: // legacy logic @@ -518,99 +474,6 @@ } switch (reg) { -#if defined(__x86_64__) -// the 32-bit field carries more detail, so we don't have to reinvent -// the wheel -#define FPR_ENV(x) ((struct envxmm32 *)m_fpr.fpr_env)->x -#else -#define FPR_ENV(x) ((struct envxmm *)m_fpr.xmm_env)->x -#endif - case lldb_fctrl_x86_64: - reg_value = (uint16_t)FPR_ENV(en_cw); - break; - case lldb_fstat_x86_64: - reg_value = (uint16_t)FPR_ENV(en_sw); - break; - case lldb_ftag_x86_64: - reg_value = (uint16_t)FPR_ENV(en_tw); - break; - case lldb_fop_x86_64: - reg_value = (uint16_t)FPR_ENV(en_opcode); - break; - case lldb_fiseg_x86_64: - reg_value = (uint32_t)FPR_ENV(en_fcs); - break; - case lldb_fioff_x86_64: - reg_value = (uint32_t)FPR_ENV(en_fip); - break; - case lldb_foseg_x86_64: - reg_value = (uint32_t)FPR_ENV(en_fos); - break; - case lldb_fooff_x86_64: - reg_value = (uint32_t)FPR_ENV(en_foo); - break; - case lldb_mxcsr_x86_64: - reg_value = (uint32_t)FPR_ENV(en_mxcsr); - break; - case lldb_mxcsrmask_x86_64: - reg_value = (uint32_t)FPR_ENV(en_mxcsr_mask); - break; - case lldb_st0_x86_64: - case lldb_st1_x86_64: - case lldb_st2_x86_64: - case lldb_st3_x86_64: - case lldb_st4_x86_64: - case lldb_st5_x86_64: - case lldb_st6_x86_64: - case lldb_st7_x86_64: -#if defined(__x86_64__) - reg_value.SetBytes(&m_fpr.fpr_acc[reg - lldb_st0_x86_64], - reg_info->byte_size, endian::InlHostByteOrder()); -#else - reg_value.SetBytes(&m_fpr.xmm_acc[reg - lldb_st0_x86_64], - reg_info->byte_size, endian::InlHostByteOrder()); -#endif - break; - case lldb_mm0_x86_64: - case lldb_mm1_x86_64: - case lldb_mm2_x86_64: - case lldb_mm3_x86_64: - case lldb_mm4_x86_64: - case lldb_mm5_x86_64: - case lldb_mm6_x86_64: - case lldb_mm7_x86_64: -#if defined(__x86_64__) - reg_value.SetBytes(&m_fpr.fpr_acc[reg - lldb_mm0_x86_64], - reg_info->byte_size, endian::InlHostByteOrder()); -#else - reg_value.SetBytes(&m_fpr.xmm_acc[reg - lldb_mm0_x86_64], - reg_info->byte_size, endian::InlHostByteOrder()); -#endif - break; - case lldb_xmm0_x86_64: - case lldb_xmm1_x86_64: - case lldb_xmm2_x86_64: - case lldb_xmm3_x86_64: - case lldb_xmm4_x86_64: - case lldb_xmm5_x86_64: - case lldb_xmm6_x86_64: - case lldb_xmm7_x86_64: - case lldb_xmm8_x86_64: - case lldb_xmm9_x86_64: - case lldb_xmm10_x86_64: - case lldb_xmm11_x86_64: - case lldb_xmm12_x86_64: - case lldb_xmm13_x86_64: - case lldb_xmm14_x86_64: - case lldb_xmm15_x86_64: -#if defined(__x86_64__) - reg_value.SetBytes(&m_fpr.fpr_xacc[reg - lldb_xmm0_x86_64], - reg_info->byte_size, endian::InlHostByteOrder()); -#else - reg_value.SetBytes(&m_fpr.xmm_reg[reg - lldb_xmm0_x86_64], - reg_info->byte_size, endian::InlHostByteOrder()); -#endif - break; case lldb_ymm0_x86_64: case lldb_ymm1_x86_64: case lldb_ymm2_x86_64: @@ -701,6 +564,9 @@ reg_value.GetByteSize()); return WriteRegisterSet(set); case FPRegSet: + ::memcpy(m_fpr.data() + reg_info->byte_offset - GetFPROffset(), + reg_value.GetBytes(), reg_value.GetByteSize()); + return WriteRegisterSet(set); case XSaveRegSet: case DBRegSet: // legacy logic @@ -718,92 +584,6 @@ } switch (reg) { - case lldb_fctrl_x86_64: - FPR_ENV(en_cw) = reg_value.GetAsUInt16(); - break; - case lldb_fstat_x86_64: - FPR_ENV(en_sw) = reg_value.GetAsUInt16(); - break; - case lldb_ftag_x86_64: - FPR_ENV(en_tw) = reg_value.GetAsUInt16(); - break; - case lldb_fop_x86_64: - FPR_ENV(en_opcode) = reg_value.GetAsUInt16(); - break; - case lldb_fiseg_x86_64: - FPR_ENV(en_fcs) = reg_value.GetAsUInt32(); - break; - case lldb_fioff_x86_64: - FPR_ENV(en_fip) = reg_value.GetAsUInt32(); - break; - case lldb_foseg_x86_64: - FPR_ENV(en_fos) = reg_value.GetAsUInt32(); - break; - case lldb_fooff_x86_64: - FPR_ENV(en_foo) = reg_value.GetAsUInt32(); - break; - case lldb_mxcsr_x86_64: - FPR_ENV(en_mxcsr) = reg_value.GetAsUInt32(); - break; - case lldb_mxcsrmask_x86_64: - FPR_ENV(en_mxcsr_mask) = reg_value.GetAsUInt32(); - break; - case lldb_st0_x86_64: - case lldb_st1_x86_64: - case lldb_st2_x86_64: - case lldb_st3_x86_64: - case lldb_st4_x86_64: - case lldb_st5_x86_64: - case lldb_st6_x86_64: - case lldb_st7_x86_64: -#if defined(__x86_64__) - ::memcpy(&m_fpr.fpr_acc[reg - lldb_st0_x86_64], reg_value.GetBytes(), - reg_value.GetByteSize()); -#else - ::memcpy(&m_fpr.xmm_acc[reg - lldb_st0_x86_64], reg_value.GetBytes(), - reg_value.GetByteSize()); -#endif - break; - case lldb_mm0_x86_64: - case lldb_mm1_x86_64: - case lldb_mm2_x86_64: - case lldb_mm3_x86_64: - case lldb_mm4_x86_64: - case lldb_mm5_x86_64: - case lldb_mm6_x86_64: - case lldb_mm7_x86_64: -#if defined(__x86_64__) - ::memcpy(&m_fpr.fpr_acc[reg - lldb_mm0_x86_64], reg_value.GetBytes(), - reg_value.GetByteSize()); -#else - ::memcpy(&m_fpr.xmm_acc[reg - lldb_mm0_x86_64], reg_value.GetBytes(), - reg_value.GetByteSize()); -#endif - break; - case lldb_xmm0_x86_64: - case lldb_xmm1_x86_64: - case lldb_xmm2_x86_64: - case lldb_xmm3_x86_64: - case lldb_xmm4_x86_64: - case lldb_xmm5_x86_64: - case lldb_xmm6_x86_64: - case lldb_xmm7_x86_64: - case lldb_xmm8_x86_64: - case lldb_xmm9_x86_64: - case lldb_xmm10_x86_64: - case lldb_xmm11_x86_64: - case lldb_xmm12_x86_64: - case lldb_xmm13_x86_64: - case lldb_xmm14_x86_64: - case lldb_xmm15_x86_64: -#if defined(__x86_64__) - ::memcpy(&m_fpr.fpr_xacc[reg - lldb_xmm0_x86_64], reg_value.GetBytes(), - reg_value.GetByteSize()); -#else - ::memcpy(&m_fpr.xmm_reg[reg - lldb_xmm0_x86_64], reg_value.GetBytes(), - reg_value.GetByteSize()); -#endif - break; case lldb_ymm0_x86_64: case lldb_ymm1_x86_64: case lldb_ymm2_x86_64: @@ -933,4 +713,20 @@ return res.ToError(); } +size_t NativeRegisterContextFreeBSD_x86_64::GetFPROffset() const { + uint32_t regno; + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { + case llvm::Triple::x86: + regno = lldb_fctrl_i386; + break; + case llvm::Triple::x86_64: + regno = lldb_fctrl_x86_64; + break; + default: + llvm_unreachable("Unhandled target architecture."); + } + + return GetRegisterInfoInterface().GetRegisterInfo()[regno].byte_offset; +} + #endif // defined(__x86_64__) diff --git a/lldb/unittests/Process/Utility/RegisterContextFreeBSDTest.cpp b/lldb/unittests/Process/Utility/RegisterContextFreeBSDTest.cpp --- a/lldb/unittests/Process/Utility/RegisterContextFreeBSDTest.cpp +++ b/lldb/unittests/Process/Utility/RegisterContextFreeBSDTest.cpp @@ -29,6 +29,10 @@ return {info.byte_offset, info.byte_size}; } +#define EXPECT_OFF(regname, offset, size) \ + EXPECT_THAT(GetRegParams(reg_ctx, lldb_##regname), \ + ::testing::Pair(offset + base_offset, size)) + #if defined(__x86_64__) #define EXPECT_GPR_X86_64(regname) \ @@ -64,6 +68,57 @@ EXPECT_GPR_X86_64(rflags); EXPECT_GPR_X86_64(rsp); EXPECT_GPR_X86_64(ss); + + // fctrl is the first FPR field, it is used to determine offset of the whole + // FPR struct + size_t base_offset = reg_ctx.GetRegisterInfo()[lldb_fctrl_x86_64].byte_offset; + + // assert against FXSAVE struct + EXPECT_OFF(fctrl_x86_64, 0x00, 2); + EXPECT_OFF(fstat_x86_64, 0x02, 2); + // TODO: This is a known bug, abridged ftag should is 8 bits in length. + EXPECT_OFF(ftag_x86_64, 0x04, 2); + EXPECT_OFF(fop_x86_64, 0x06, 2); + // NB: Technically fiseg/foseg are 16-bit long and the higher 16 bits + // are reserved. However, we use them to access/recombine 64-bit FIP/FDP. + EXPECT_OFF(fioff_x86_64, 0x08, 4); + EXPECT_OFF(fiseg_x86_64, 0x0C, 4); + EXPECT_OFF(fooff_x86_64, 0x10, 4); + EXPECT_OFF(foseg_x86_64, 0x14, 4); + EXPECT_OFF(mxcsr_x86_64, 0x18, 4); + EXPECT_OFF(mxcsrmask_x86_64, 0x1C, 4); + EXPECT_OFF(st0_x86_64, 0x20, 10); + EXPECT_OFF(st1_x86_64, 0x30, 10); + EXPECT_OFF(st2_x86_64, 0x40, 10); + EXPECT_OFF(st3_x86_64, 0x50, 10); + EXPECT_OFF(st4_x86_64, 0x60, 10); + EXPECT_OFF(st5_x86_64, 0x70, 10); + EXPECT_OFF(st6_x86_64, 0x80, 10); + EXPECT_OFF(st7_x86_64, 0x90, 10); + EXPECT_OFF(mm0_x86_64, 0x20, 8); + EXPECT_OFF(mm1_x86_64, 0x30, 8); + EXPECT_OFF(mm2_x86_64, 0x40, 8); + EXPECT_OFF(mm3_x86_64, 0x50, 8); + EXPECT_OFF(mm4_x86_64, 0x60, 8); + EXPECT_OFF(mm5_x86_64, 0x70, 8); + EXPECT_OFF(mm6_x86_64, 0x80, 8); + EXPECT_OFF(mm7_x86_64, 0x90, 8); + EXPECT_OFF(xmm0_x86_64, 0xA0, 16); + EXPECT_OFF(xmm1_x86_64, 0xB0, 16); + EXPECT_OFF(xmm2_x86_64, 0xC0, 16); + EXPECT_OFF(xmm3_x86_64, 0xD0, 16); + EXPECT_OFF(xmm4_x86_64, 0xE0, 16); + EXPECT_OFF(xmm5_x86_64, 0xF0, 16); + EXPECT_OFF(xmm6_x86_64, 0x100, 16); + EXPECT_OFF(xmm7_x86_64, 0x110, 16); + EXPECT_OFF(xmm8_x86_64, 0x120, 16); + EXPECT_OFF(xmm9_x86_64, 0x130, 16); + EXPECT_OFF(xmm10_x86_64, 0x140, 16); + EXPECT_OFF(xmm11_x86_64, 0x150, 16); + EXPECT_OFF(xmm12_x86_64, 0x160, 16); + EXPECT_OFF(xmm13_x86_64, 0x170, 16); + EXPECT_OFF(xmm14_x86_64, 0x180, 16); + EXPECT_OFF(xmm15_x86_64, 0x190, 16); } #endif // defined(__x86_64__) @@ -101,6 +156,49 @@ EXPECT_GPR_I386(esp); EXPECT_GPR_I386(ss); EXPECT_GPR_I386(gs); + + // fctrl is the first FPR field, it is used to determine offset of the whole + // FPR struct + size_t base_offset = reg_ctx.GetRegisterInfo()[lldb_fctrl_i386].byte_offset; + + // assert against FXSAVE struct + EXPECT_OFF(fctrl_i386, 0x00, 2); + EXPECT_OFF(fstat_i386, 0x02, 2); + // TODO: This is a known bug, abridged ftag should is 8 bits in length. + EXPECT_OFF(ftag_i386, 0x04, 2); + EXPECT_OFF(fop_i386, 0x06, 2); + // NB: Technically fiseg/foseg are 16-bit long and the higher 16 bits + // are reserved. However, we use them to access/recombine 64-bit FIP/FDP. + EXPECT_OFF(fioff_i386, 0x08, 4); + EXPECT_OFF(fiseg_i386, 0x0C, 4); + EXPECT_OFF(fooff_i386, 0x10, 4); + EXPECT_OFF(foseg_i386, 0x14, 4); + EXPECT_OFF(mxcsr_i386, 0x18, 4); + EXPECT_OFF(mxcsrmask_i386, 0x1C, 4); + EXPECT_OFF(st0_i386, 0x20, 10); + EXPECT_OFF(st1_i386, 0x30, 10); + EXPECT_OFF(st2_i386, 0x40, 10); + EXPECT_OFF(st3_i386, 0x50, 10); + EXPECT_OFF(st4_i386, 0x60, 10); + EXPECT_OFF(st5_i386, 0x70, 10); + EXPECT_OFF(st6_i386, 0x80, 10); + EXPECT_OFF(st7_i386, 0x90, 10); + EXPECT_OFF(mm0_i386, 0x20, 8); + EXPECT_OFF(mm1_i386, 0x30, 8); + EXPECT_OFF(mm2_i386, 0x40, 8); + EXPECT_OFF(mm3_i386, 0x50, 8); + EXPECT_OFF(mm4_i386, 0x60, 8); + EXPECT_OFF(mm5_i386, 0x70, 8); + EXPECT_OFF(mm6_i386, 0x80, 8); + EXPECT_OFF(mm7_i386, 0x90, 8); + EXPECT_OFF(xmm0_i386, 0xA0, 16); + EXPECT_OFF(xmm1_i386, 0xB0, 16); + EXPECT_OFF(xmm2_i386, 0xC0, 16); + EXPECT_OFF(xmm3_i386, 0xD0, 16); + EXPECT_OFF(xmm4_i386, 0xE0, 16); + EXPECT_OFF(xmm5_i386, 0xF0, 16); + EXPECT_OFF(xmm6_i386, 0x100, 16); + EXPECT_OFF(xmm7_i386, 0x110, 16); } #endif // defined(__i386__) || defined(__x86_64__)