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 @@ -71,17 +71,17 @@ // Private member variables. std::array m_gpr; std::array m_fpr; // FXSAVE - struct dbreg m_dbr; + std::array m_dbr; std::vector m_xsave; std::array m_xsave_offsets; llvm::Optional GetSetForNativeRegNum(int reg_num) const; - int GetDR(int num) const; Status ReadRegisterSet(uint32_t set); Status WriteRegisterSet(uint32_t set); size_t GetFPROffset() const; + size_t GetDBROffset() 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 @@ -247,8 +247,7 @@ NativeRegisterContextFreeBSD_x86_64::NativeRegisterContextFreeBSD_x86_64( const ArchSpec &target_arch, NativeThreadProtocol &native_thread) : NativeRegisterContextRegisterInfo( - native_thread, CreateRegisterInfoInterface(target_arch)), - m_dbr() { + native_thread, CreateRegisterInfoInterface(target_arch)) { assert(m_gpr.size() == GetRegisterInfoInterface().GetGPRSize()); } @@ -296,15 +295,6 @@ return lldb_bndcfgu_x86_64; case lldb_bndstatus_i386: return lldb_bndstatus_x86_64; - case lldb_dr0_i386: - case lldb_dr1_i386: - case lldb_dr2_i386: - case lldb_dr3_i386: - case lldb_dr4_i386: - case lldb_dr5_i386: - case lldb_dr6_i386: - case lldb_dr7_i386: - return lldb_dr0_x86_64 + regnum - lldb_dr0_i386; default: llvm_unreachable("Unhandled i386 register."); } @@ -363,7 +353,7 @@ #endif case DBRegSet: return NativeProcessFreeBSD::PtraceWrapper(PT_GETDBREGS, m_thread.GetID(), - &m_dbr); + m_dbr.data()); case XSaveRegSet: { struct ptrace_xstate_info info; Status ret = NativeProcessFreeBSD::PtraceWrapper( @@ -404,7 +394,7 @@ #endif case DBRegSet: return NativeProcessFreeBSD::PtraceWrapper(PT_SETDBREGS, m_thread.GetID(), - &m_dbr); + m_dbr.data()); case XSaveRegSet: // ReadRegisterSet() must always be called before WriteRegisterSet(). assert(m_xsave.size() > 0); @@ -457,8 +447,11 @@ reg_value.SetBytes(m_fpr.data() + reg_info->byte_offset - GetFPROffset(), reg_info->byte_size, endian::InlHostByteOrder()); return error; - case XSaveRegSet: case DBRegSet: + reg_value.SetBytes(m_dbr.data() + reg_info->byte_offset - GetDBROffset(), + reg_info->byte_size, endian::InlHostByteOrder()); + return error; + case XSaveRegSet: // legacy logic break; } @@ -507,16 +500,6 @@ } break; } - case lldb_dr0_x86_64: - case lldb_dr1_x86_64: - case lldb_dr2_x86_64: - case lldb_dr3_x86_64: - case lldb_dr4_x86_64: - case lldb_dr5_x86_64: - case lldb_dr6_x86_64: - case lldb_dr7_x86_64: - reg_value = (uint64_t)m_dbr.dr[reg - lldb_dr0_x86_64]; - break; default: llvm_unreachable("Reading unknown/unsupported register"); } @@ -567,8 +550,11 @@ ::memcpy(m_fpr.data() + reg_info->byte_offset - GetFPROffset(), reg_value.GetBytes(), reg_value.GetByteSize()); return WriteRegisterSet(set); - case XSaveRegSet: case DBRegSet: + ::memcpy(m_dbr.data() + reg_info->byte_offset - GetDBROffset(), + reg_value.GetBytes(), reg_value.GetByteSize()); + return WriteRegisterSet(set); + case XSaveRegSet: // legacy logic break; } @@ -616,16 +602,6 @@ } break; } - case lldb_dr0_x86_64: - case lldb_dr1_x86_64: - case lldb_dr2_x86_64: - case lldb_dr3_x86_64: - case lldb_dr4_x86_64: - case lldb_dr5_x86_64: - case lldb_dr6_x86_64: - case lldb_dr7_x86_64: - m_dbr.dr[reg - lldb_dr0_x86_64] = reg_value.GetAsUInt64(); - break; default: llvm_unreachable("Reading unknown/unsupported register"); } @@ -686,25 +662,15 @@ return error; } -int NativeRegisterContextFreeBSD_x86_64::GetDR(int num) const { - assert(num >= 0 && num <= 7); - switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { - case llvm::Triple::x86: - return lldb_dr0_i386 + num; - case llvm::Triple::x86_64: - return lldb_dr0_x86_64 + num; - default: - llvm_unreachable("Unhandled target architecture."); - } -} - llvm::Error NativeRegisterContextFreeBSD_x86_64::CopyHardwareWatchpointsFrom( NativeRegisterContextFreeBSD &source) { auto &r_source = static_cast(source); - Status res = r_source.ReadRegisterSet(DBRegSet); + // NB: This implicitly reads the whole dbreg set. + RegisterValue dr7; + Status res = r_source.ReadRegister(GetDR(7), dr7); if (!res.Fail()) { // copy dbregs only if any watchpoints were set - if ((r_source.m_dbr.dr[7] & 0xFF) == 0) + if ((dr7.GetAsUInt64() & 0xFF) == 0) return llvm::Error::success(); m_dbr = r_source.m_dbr; @@ -729,4 +695,20 @@ return GetRegisterInfoInterface().GetRegisterInfo()[regno].byte_offset; } +size_t NativeRegisterContextFreeBSD_x86_64::GetDBROffset() const { + uint32_t regno; + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { + case llvm::Triple::x86: + regno = lldb_dr0_i386; + break; + case llvm::Triple::x86_64: + regno = lldb_dr0_x86_64; + break; + default: + llvm_unreachable("Unhandled target architecture."); + } + + return GetRegisterInfoInterface().GetRegisterInfo()[regno].byte_offset; +} + #endif // defined(__x86_64__) diff --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextWatchpoint_x86.h b/lldb/source/Plugins/Process/Utility/NativeRegisterContextWatchpoint_x86.h --- a/lldb/source/Plugins/Process/Utility/NativeRegisterContextWatchpoint_x86.h +++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextWatchpoint_x86.h @@ -40,7 +40,6 @@ uint32_t NumSupportedHardwareWatchpoints() override; -private: const RegisterInfo *GetDR(int num) const; }; 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 @@ -39,6 +39,8 @@ EXPECT_THAT( \ GetRegParams(reg_ctx, lldb_##regname##_x86_64), \ ::testing::Pair(offsetof(reg, r_##regname), sizeof(reg::r_##regname))) +#define EXPECT_DBR_X86_64(num) \ + EXPECT_OFF(dr##num##_x86_64, offsetof(dbreg, dr[num]), sizeof(dbreg::dr[num])) TEST(RegisterContextFreeBSDTest, x86_64) { ArchSpec arch{"x86_64-unknown-freebsd"}; @@ -119,6 +121,16 @@ EXPECT_OFF(xmm13_x86_64, 0x170, 16); EXPECT_OFF(xmm14_x86_64, 0x180, 16); EXPECT_OFF(xmm15_x86_64, 0x190, 16); + + base_offset = reg_ctx.GetRegisterInfo()[lldb_dr0_x86_64].byte_offset; + EXPECT_DBR_X86_64(0); + EXPECT_DBR_X86_64(1); + EXPECT_DBR_X86_64(2); + EXPECT_DBR_X86_64(3); + EXPECT_DBR_X86_64(4); + EXPECT_DBR_X86_64(5); + EXPECT_DBR_X86_64(6); + EXPECT_DBR_X86_64(7); } #endif // defined(__x86_64__) @@ -129,6 +141,9 @@ EXPECT_THAT(GetRegParams(reg_ctx, lldb_##regname##_i386), \ ::testing::Pair(offsetof(native_i386_regs, r_##regname), \ sizeof(native_i386_regs::r_##regname))) +#define EXPECT_DBR_I386(num) \ + EXPECT_OFF(dr##num##_i386, offsetof(native_i386_dbregs, dr[num]), \ + sizeof(native_i386_dbregs::dr[num])) TEST(RegisterContextFreeBSDTest, i386) { ArchSpec arch{"i686-unknown-freebsd"}; @@ -136,8 +151,10 @@ #if defined(__i386__) using native_i386_regs = ::reg; + using native_i386_dbregs = ::dbreg; #else using native_i386_regs = ::reg32; + using native_i386_dbregs = ::dbreg32; #endif EXPECT_GPR_I386(fs); @@ -199,6 +216,16 @@ EXPECT_OFF(xmm5_i386, 0xF0, 16); EXPECT_OFF(xmm6_i386, 0x100, 16); EXPECT_OFF(xmm7_i386, 0x110, 16); + + base_offset = reg_ctx.GetRegisterInfo()[lldb_dr0_i386].byte_offset; + EXPECT_DBR_I386(0); + EXPECT_DBR_I386(1); + EXPECT_DBR_I386(2); + EXPECT_DBR_I386(3); + EXPECT_DBR_I386(4); + EXPECT_DBR_I386(5); + EXPECT_DBR_I386(6); + EXPECT_DBR_I386(7); } #endif // defined(__i386__) || defined(__x86_64__)