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 @@ -18,6 +18,8 @@ #include // clang-format on +#include + #include "Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD.h" #include "Plugins/Process/Utility/RegisterContext_x86.h" #include "Plugins/Process/Utility/NativeRegisterContextWatchpoint_x86.h" @@ -55,14 +57,19 @@ private: // Private member types. - enum { GPRegSet, FPRegSet, XSaveRegSet, DBRegSet }; + enum RegSetKind { + GPRegSet, + FPRegSet, + XSaveRegSet, + DBRegSet, + }; enum { YMMXSaveSet, MaxXSaveSet = YMMXSaveSet, }; // Private member variables. - struct reg m_gpr; + std::array m_gpr; #if defined(__x86_64__) struct fpreg m_fpr; #else @@ -72,7 +79,7 @@ std::vector m_xsave; std::array m_xsave_offsets; - int GetSetForNativeRegNum(int reg_num) const; + llvm::Optional GetSetForNativeRegNum(int reg_num) const; int GetDR(int num) const; Status ReadRegisterSet(uint32_t set); 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,14 +248,16 @@ const ArchSpec &target_arch, NativeThreadProtocol &native_thread) : NativeRegisterContextRegisterInfo( native_thread, CreateRegisterInfoInterface(target_arch)), - m_gpr(), m_fpr(), m_dbr() {} + m_fpr(), m_dbr() { + assert(m_gpr.size() == GetRegisterInfoInterface().GetGPRSize()); +} // CONSIDER after local and llgs debugging are merged, register set support can // be moved into a base x86-64 class with IsRegisterSetAvailable made virtual. uint32_t NativeRegisterContextFreeBSD_x86_64::GetRegisterSetCount() const { uint32_t sets = 0; for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) { - if (GetSetForNativeRegNum(set_index) != -1) + if (GetSetForNativeRegNum(set_index)) ++sets; } @@ -276,38 +278,6 @@ static constexpr int RegNumX86ToX86_64(int regnum) { switch (regnum) { - case lldb_eax_i386: - return lldb_rax_x86_64; - case lldb_ebx_i386: - return lldb_rbx_x86_64; - case lldb_ecx_i386: - return lldb_rcx_x86_64; - case lldb_edx_i386: - return lldb_rdx_x86_64; - case lldb_edi_i386: - return lldb_rdi_x86_64; - case lldb_esi_i386: - return lldb_rsi_x86_64; - case lldb_ebp_i386: - return lldb_rbp_x86_64; - case lldb_esp_i386: - return lldb_rsp_x86_64; - case lldb_eip_i386: - return lldb_rip_x86_64; - case lldb_eflags_i386: - return lldb_rflags_x86_64; - case lldb_cs_i386: - return lldb_cs_x86_64; - case lldb_fs_i386: - return lldb_fs_x86_64; - case lldb_gs_i386: - return lldb_gs_x86_64; - case lldb_ss_i386: - return lldb_ss_x86_64; - case lldb_ds_i386: - return lldb_ds_x86_64; - case lldb_es_i386: - return lldb_es_x86_64; case lldb_fctrl_i386: return lldb_fctrl_x86_64; case lldb_fstat_i386: @@ -387,9 +357,8 @@ } } -int NativeRegisterContextFreeBSD_x86_64::GetSetForNativeRegNum( - int reg_num) const { - +llvm::Optional +NativeRegisterContextFreeBSD_x86_64::GetSetForNativeRegNum(int reg_num) const { switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { case llvm::Triple::x86: if (reg_num >= k_first_gpr_i386 && reg_num <= k_last_gpr_i386) @@ -399,9 +368,9 @@ if (reg_num >= k_first_avx_i386 && reg_num <= k_last_avx_i386) return XSaveRegSet; // AVX if (reg_num >= k_first_mpxr_i386 && reg_num <= k_last_mpxr_i386) - return -1; // MPXR + return llvm::None; // MPXR if (reg_num >= k_first_mpxc_i386 && reg_num <= k_last_mpxc_i386) - return -1; // MPXC + return llvm::None; // MPXC if (reg_num >= k_first_dbr_i386 && reg_num <= k_last_dbr_i386) return DBRegSet; // DBR break; @@ -413,9 +382,9 @@ if (reg_num >= k_first_avx_x86_64 && reg_num <= k_last_avx_x86_64) return XSaveRegSet; // AVX if (reg_num >= k_first_mpxr_x86_64 && reg_num <= k_last_mpxr_x86_64) - return -1; // MPXR + return llvm::None; // MPXR if (reg_num >= k_first_mpxc_x86_64 && reg_num <= k_last_mpxc_x86_64) - return -1; // MPXC + return llvm::None; // MPXC if (reg_num >= k_first_dbr_x86_64 && reg_num <= k_last_dbr_x86_64) return DBRegSet; // DBR break; @@ -430,7 +399,7 @@ switch (set) { case GPRegSet: return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(), - &m_gpr); + m_gpr.data()); case FPRegSet: #if defined(__x86_64__) return NativeProcessFreeBSD::PtraceWrapper(PT_GETFPREGS, m_thread.GetID(), @@ -471,7 +440,7 @@ switch (set) { case GPRegSet: return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(), - &m_gpr); + m_gpr.data()); case FPRegSet: #if defined(__x86_64__) return NativeProcessFreeBSD::PtraceWrapper(PT_SETFPREGS, m_thread.GetID(), @@ -512,8 +481,8 @@ return error; } - int set = GetSetForNativeRegNum(reg); - if (set == -1) { + llvm::Optional opt_set = GetSetForNativeRegNum(reg); + if (!opt_set) { // This is likely an internal register for lldb use only and should not be // directly queried. error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set", @@ -521,6 +490,23 @@ return error; } + enum RegSetKind set = opt_set.getValue(); + error = ReadRegisterSet(set); + if (error.Fail()) + return error; + + switch (set) { + case GPRegSet: + reg_value.SetBytes(m_gpr.data() + reg_info->byte_offset, + reg_info->byte_size, endian::InlHostByteOrder()); + return error; + case FPRegSet: + case XSaveRegSet: + case DBRegSet: + // legacy logic + break; + } + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { case llvm::Triple::x86_64: break; @@ -531,134 +517,7 @@ llvm_unreachable("Unhandled target architecture."); } - error = ReadRegisterSet(set); - if (error.Fail()) - return error; - switch (reg) { -#if defined(__x86_64__) - case lldb_rax_x86_64: - reg_value = (uint64_t)m_gpr.r_rax; - break; - case lldb_rbx_x86_64: - reg_value = (uint64_t)m_gpr.r_rbx; - break; - case lldb_rcx_x86_64: - reg_value = (uint64_t)m_gpr.r_rcx; - break; - case lldb_rdx_x86_64: - reg_value = (uint64_t)m_gpr.r_rdx; - break; - case lldb_rdi_x86_64: - reg_value = (uint64_t)m_gpr.r_rdi; - break; - case lldb_rsi_x86_64: - reg_value = (uint64_t)m_gpr.r_rsi; - break; - case lldb_rbp_x86_64: - reg_value = (uint64_t)m_gpr.r_rbp; - break; - case lldb_rsp_x86_64: - reg_value = (uint64_t)m_gpr.r_rsp; - break; - case lldb_r8_x86_64: - reg_value = (uint64_t)m_gpr.r_r8; - break; - case lldb_r9_x86_64: - reg_value = (uint64_t)m_gpr.r_r9; - break; - case lldb_r10_x86_64: - reg_value = (uint64_t)m_gpr.r_r10; - break; - case lldb_r11_x86_64: - reg_value = (uint64_t)m_gpr.r_r11; - break; - case lldb_r12_x86_64: - reg_value = (uint64_t)m_gpr.r_r12; - break; - case lldb_r13_x86_64: - reg_value = (uint64_t)m_gpr.r_r13; - break; - case lldb_r14_x86_64: - reg_value = (uint64_t)m_gpr.r_r14; - break; - case lldb_r15_x86_64: - reg_value = (uint64_t)m_gpr.r_r15; - break; - case lldb_rip_x86_64: - reg_value = (uint64_t)m_gpr.r_rip; - break; - case lldb_rflags_x86_64: - reg_value = (uint64_t)m_gpr.r_rflags; - break; - case lldb_cs_x86_64: - reg_value = (uint64_t)m_gpr.r_cs; - break; - case lldb_fs_x86_64: - reg_value = (uint16_t)m_gpr.r_fs; - break; - case lldb_gs_x86_64: - reg_value = (uint16_t)m_gpr.r_gs; - break; - case lldb_ss_x86_64: - reg_value = (uint64_t)m_gpr.r_ss; - break; - case lldb_ds_x86_64: - reg_value = (uint16_t)m_gpr.r_ds; - break; - case lldb_es_x86_64: - reg_value = (uint16_t)m_gpr.r_es; - break; -#else - case lldb_rax_x86_64: - reg_value = (uint32_t)m_gpr.r_eax; - break; - case lldb_rbx_x86_64: - reg_value = (uint32_t)m_gpr.r_ebx; - break; - case lldb_rcx_x86_64: - reg_value = (uint32_t)m_gpr.r_ecx; - break; - case lldb_rdx_x86_64: - reg_value = (uint32_t)m_gpr.r_edx; - break; - case lldb_rdi_x86_64: - reg_value = (uint32_t)m_gpr.r_edi; - break; - case lldb_rsi_x86_64: - reg_value = (uint32_t)m_gpr.r_esi; - break; - case lldb_rsp_x86_64: - reg_value = (uint32_t)m_gpr.r_esp; - break; - case lldb_rbp_x86_64: - reg_value = (uint32_t)m_gpr.r_ebp; - break; - case lldb_rip_x86_64: - reg_value = (uint32_t)m_gpr.r_eip; - break; - case lldb_rflags_x86_64: - reg_value = (uint32_t)m_gpr.r_eflags; - break; - case lldb_cs_x86_64: - reg_value = (uint32_t)m_gpr.r_cs; - break; - case lldb_fs_x86_64: - reg_value = (uint16_t)m_gpr.r_fs; - break; - case lldb_gs_x86_64: - reg_value = (uint16_t)m_gpr.r_gs; - break; - case lldb_ss_x86_64: - reg_value = (uint32_t)m_gpr.r_ss; - break; - case lldb_ds_x86_64: - reg_value = (uint16_t)m_gpr.r_ds; - break; - case lldb_es_x86_64: - reg_value = (uint16_t)m_gpr.r_es; - break; -#endif #if defined(__x86_64__) // the 32-bit field carries more detail, so we don't have to reinvent // the wheel @@ -822,8 +681,8 @@ return error; } - int set = GetSetForNativeRegNum(reg); - if (set == -1) { + llvm::Optional opt_set = GetSetForNativeRegNum(reg); + if (!opt_set) { // This is likely an internal register for lldb use only and should not be // directly queried. error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set", @@ -831,6 +690,23 @@ return error; } + enum RegSetKind set = opt_set.getValue(); + error = ReadRegisterSet(set); + if (error.Fail()) + return error; + + switch (set) { + case GPRegSet: + ::memcpy(m_gpr.data() + reg_info->byte_offset, reg_value.GetBytes(), + reg_value.GetByteSize()); + return WriteRegisterSet(set); + case FPRegSet: + case XSaveRegSet: + case DBRegSet: + // legacy logic + break; + } + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { case llvm::Triple::x86_64: break; @@ -841,134 +717,7 @@ llvm_unreachable("Unhandled target architecture."); } - error = ReadRegisterSet(set); - if (error.Fail()) - return error; - switch (reg) { -#if defined(__x86_64__) - case lldb_rax_x86_64: - m_gpr.r_rax = reg_value.GetAsUInt64(); - break; - case lldb_rbx_x86_64: - m_gpr.r_rbx = reg_value.GetAsUInt64(); - break; - case lldb_rcx_x86_64: - m_gpr.r_rcx = reg_value.GetAsUInt64(); - break; - case lldb_rdx_x86_64: - m_gpr.r_rdx = reg_value.GetAsUInt64(); - break; - case lldb_rdi_x86_64: - m_gpr.r_rdi = reg_value.GetAsUInt64(); - break; - case lldb_rsi_x86_64: - m_gpr.r_rsi = reg_value.GetAsUInt64(); - break; - case lldb_rbp_x86_64: - m_gpr.r_rbp = reg_value.GetAsUInt64(); - break; - case lldb_rsp_x86_64: - m_gpr.r_rsp = reg_value.GetAsUInt64(); - break; - case lldb_r8_x86_64: - m_gpr.r_r8 = reg_value.GetAsUInt64(); - break; - case lldb_r9_x86_64: - m_gpr.r_r9 = reg_value.GetAsUInt64(); - break; - case lldb_r10_x86_64: - m_gpr.r_r10 = reg_value.GetAsUInt64(); - break; - case lldb_r11_x86_64: - m_gpr.r_r11 = reg_value.GetAsUInt64(); - break; - case lldb_r12_x86_64: - m_gpr.r_r12 = reg_value.GetAsUInt64(); - break; - case lldb_r13_x86_64: - m_gpr.r_r13 = reg_value.GetAsUInt64(); - break; - case lldb_r14_x86_64: - m_gpr.r_r14 = reg_value.GetAsUInt64(); - break; - case lldb_r15_x86_64: - m_gpr.r_r15 = reg_value.GetAsUInt64(); - break; - case lldb_rip_x86_64: - m_gpr.r_rip = reg_value.GetAsUInt64(); - break; - case lldb_rflags_x86_64: - m_gpr.r_rflags = reg_value.GetAsUInt64(); - break; - case lldb_cs_x86_64: - m_gpr.r_cs = reg_value.GetAsUInt64(); - break; - case lldb_fs_x86_64: - m_gpr.r_fs = reg_value.GetAsUInt16(); - break; - case lldb_gs_x86_64: - m_gpr.r_gs = reg_value.GetAsUInt16(); - break; - case lldb_ss_x86_64: - m_gpr.r_ss = reg_value.GetAsUInt64(); - break; - case lldb_ds_x86_64: - m_gpr.r_ds = reg_value.GetAsUInt16(); - break; - case lldb_es_x86_64: - m_gpr.r_es = reg_value.GetAsUInt16(); - break; -#else - case lldb_rax_x86_64: - m_gpr.r_eax = reg_value.GetAsUInt32(); - break; - case lldb_rbx_x86_64: - m_gpr.r_ebx = reg_value.GetAsUInt32(); - break; - case lldb_rcx_x86_64: - m_gpr.r_ecx = reg_value.GetAsUInt32(); - break; - case lldb_rdx_x86_64: - m_gpr.r_edx = reg_value.GetAsUInt32(); - break; - case lldb_rdi_x86_64: - m_gpr.r_edi = reg_value.GetAsUInt32(); - break; - case lldb_rsi_x86_64: - m_gpr.r_esi = reg_value.GetAsUInt32(); - break; - case lldb_rsp_x86_64: - m_gpr.r_esp = reg_value.GetAsUInt32(); - break; - case lldb_rbp_x86_64: - m_gpr.r_ebp = reg_value.GetAsUInt32(); - break; - case lldb_rip_x86_64: - m_gpr.r_eip = reg_value.GetAsUInt32(); - break; - case lldb_rflags_x86_64: - m_gpr.r_eflags = reg_value.GetAsUInt32(); - break; - case lldb_cs_x86_64: - m_gpr.r_cs = reg_value.GetAsUInt32(); - break; - case lldb_fs_x86_64: - m_gpr.r_fs = reg_value.GetAsUInt16(); - break; - case lldb_gs_x86_64: - m_gpr.r_gs = reg_value.GetAsUInt16(); - break; - case lldb_ss_x86_64: - m_gpr.r_ss = reg_value.GetAsUInt32(); - break; - case lldb_ds_x86_64: - m_gpr.r_ds = reg_value.GetAsUInt16(); - break; - case lldb_es_x86_64: - m_gpr.r_es = reg_value.GetAsUInt16(); - break; -#endif case lldb_fctrl_x86_64: FPR_ENV(en_cw) = reg_value.GetAsUInt16(); break; @@ -1114,7 +863,7 @@ return error; uint8_t *dst = data_sp->GetBytes(); - ::memcpy(dst, &m_gpr, GetRegisterInfoInterface().GetGPRSize()); + ::memcpy(dst, m_gpr.data(), GetRegisterInfoInterface().GetGPRSize()); dst += GetRegisterInfoInterface().GetGPRSize(); return error; @@ -1147,7 +896,7 @@ __FUNCTION__); return error; } - ::memcpy(&m_gpr, src, GetRegisterInfoInterface().GetGPRSize()); + ::memcpy(m_gpr.data(), src, GetRegisterInfoInterface().GetGPRSize()); error = WriteRegisterSet(GPRegSet); if (error.Fail()) diff --git a/lldb/unittests/Process/CMakeLists.txt b/lldb/unittests/Process/CMakeLists.txt --- a/lldb/unittests/Process/CMakeLists.txt +++ b/lldb/unittests/Process/CMakeLists.txt @@ -3,6 +3,7 @@ add_subdirectory(Linux) add_subdirectory(POSIX) endif() +add_subdirectory(Utility) add_subdirectory(minidump) add_lldb_unittest(ProcessEventDataTests diff --git a/lldb/unittests/Process/Utility/CMakeLists.txt b/lldb/unittests/Process/Utility/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/lldb/unittests/Process/Utility/CMakeLists.txt @@ -0,0 +1,5 @@ +add_lldb_unittest(ProcessUtilityTests + RegisterContextFreeBSDTest.cpp + + LINK_LIBS + lldbPluginProcessUtility) diff --git a/lldb/unittests/Process/Utility/RegisterContextFreeBSDTest.cpp b/lldb/unittests/Process/Utility/RegisterContextFreeBSDTest.cpp new file mode 100644 --- /dev/null +++ b/lldb/unittests/Process/Utility/RegisterContextFreeBSDTest.cpp @@ -0,0 +1,108 @@ +//===-- RegisterContextFreeBSDTests.cpp -----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#if defined(__FreeBSD__) + +// clang-format off +#include +#include +// clang-format on + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include "Plugins/Process/Utility/lldb-x86-register-enums.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h" + +using namespace lldb; +using namespace lldb_private; + +std::pair GetRegParams(RegisterInfoInterface &ctx, + uint32_t reg) { + const RegisterInfo &info = ctx.GetRegisterInfo()[reg]; + return {info.byte_offset, info.byte_size}; +} + +#if defined(__x86_64__) + +#define EXPECT_GPR_X86_64(regname) \ + EXPECT_THAT( \ + GetRegParams(reg_ctx, lldb_##regname##_x86_64), \ + ::testing::Pair(offsetof(reg, r_##regname), sizeof(reg::r_##regname))) + +TEST(RegisterContextFreeBSDTest, x86_64) { + ArchSpec arch{"x86_64-unknown-freebsd"}; + RegisterContextFreeBSD_x86_64 reg_ctx{arch}; + + EXPECT_GPR_X86_64(r15); + EXPECT_GPR_X86_64(r14); + EXPECT_GPR_X86_64(r13); + EXPECT_GPR_X86_64(r12); + EXPECT_GPR_X86_64(r11); + EXPECT_GPR_X86_64(r10); + EXPECT_GPR_X86_64(r9); + EXPECT_GPR_X86_64(r8); + EXPECT_GPR_X86_64(rdi); + EXPECT_GPR_X86_64(rsi); + EXPECT_GPR_X86_64(rbp); + EXPECT_GPR_X86_64(rbx); + EXPECT_GPR_X86_64(rdx); + EXPECT_GPR_X86_64(rcx); + EXPECT_GPR_X86_64(rax); + EXPECT_GPR_X86_64(fs); + EXPECT_GPR_X86_64(gs); + EXPECT_GPR_X86_64(es); + EXPECT_GPR_X86_64(ds); + EXPECT_GPR_X86_64(rip); + EXPECT_GPR_X86_64(cs); + EXPECT_GPR_X86_64(rflags); + EXPECT_GPR_X86_64(rsp); + EXPECT_GPR_X86_64(ss); +} + +#endif // defined(__x86_64__) + +#if defined(__i386__) || defined(__x86_64__) + +#define EXPECT_GPR_I386(regname) \ + EXPECT_THAT(GetRegParams(reg_ctx, lldb_##regname##_i386), \ + ::testing::Pair(offsetof(native_i386_regs, r_##regname), \ + sizeof(native_i386_regs::r_##regname))) + +TEST(RegisterContextFreeBSDTest, i386) { + ArchSpec arch{"i686-unknown-freebsd"}; + RegisterContextFreeBSD_i386 reg_ctx{arch}; + +#if defined(__i386__) + using native_i386_regs = ::reg; +#else + using native_i386_regs = ::reg32; +#endif + + EXPECT_GPR_I386(fs); + EXPECT_GPR_I386(es); + EXPECT_GPR_I386(ds); + EXPECT_GPR_I386(edi); + EXPECT_GPR_I386(esi); + EXPECT_GPR_I386(ebp); + EXPECT_GPR_I386(ebx); + EXPECT_GPR_I386(edx); + EXPECT_GPR_I386(ecx); + EXPECT_GPR_I386(eax); + EXPECT_GPR_I386(eip); + EXPECT_GPR_I386(cs); + EXPECT_GPR_I386(eflags); + EXPECT_GPR_I386(esp); + EXPECT_GPR_I386(ss); + EXPECT_GPR_I386(gs); +} + +#endif // defined(__i386__) || defined(__x86_64__) + +#endif // defined(__FreeBSD__)