diff --git a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.h b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.h --- a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.h +++ b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.h @@ -54,8 +54,11 @@ private: enum RegSetKind { GPRegSet, + FPRegSet, }; - std::array m_reg_data; + std::array m_reg_data; + + llvm::Optional GetSetForNativeRegNum(uint32_t reg_num) const; Status ReadRegisterSet(RegSetKind set); Status WriteRegisterSet(RegSetKind set); diff --git a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.cpp b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.cpp --- a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.cpp +++ b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.cpp @@ -15,6 +15,7 @@ #include "lldb/Utility/Status.h" #include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h" +#include "Plugins/Process/Utility/lldb-mips-freebsd-register-enums.h" // clang-format off #include @@ -59,11 +60,32 @@ return count; } +llvm::Optional +NativeRegisterContextFreeBSD_mips64::GetSetForNativeRegNum( + uint32_t reg_num) const { + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { + case llvm::Triple::mips64: + if (reg_num >= k_first_gpr_mips64 && reg_num <= k_last_gpr_mips64) + return GPRegSet; + if (reg_num >= k_first_fpr_mips64 && reg_num <= k_last_fpr_mips64) + return FPRegSet; + break; + default: + llvm_unreachable("Unhandled target architecture."); + } + + llvm_unreachable("Register does not belong to any register set"); +} + Status NativeRegisterContextFreeBSD_mips64::ReadRegisterSet(RegSetKind set) { switch (set) { case GPRegSet: return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(), m_reg_data.data()); + case FPRegSet: + return NativeProcessFreeBSD::PtraceWrapper( + PT_GETFPREGS, m_thread.GetID(), + m_reg_data.data() + GetRegisterInfo().GetGPRSize()); } llvm_unreachable("NativeRegisterContextFreeBSD_mips64::ReadRegisterSet"); } @@ -73,6 +95,10 @@ case GPRegSet: return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(), m_reg_data.data()); + case FPRegSet: + return NativeProcessFreeBSD::PtraceWrapper( + PT_SETFPREGS, m_thread.GetID(), + m_reg_data.data() + GetRegisterInfo().GetGPRSize()); } llvm_unreachable("NativeRegisterContextFreeBSD_mips64::WriteRegisterSet"); } @@ -94,7 +120,16 @@ ? reg_info->name : ""); - RegSetKind set = GPRegSet; + 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", + reg_info->name); + return error; + } + + RegSetKind set = opt_set.getValue(); error = ReadRegisterSet(set); if (error.Fail()) return error; @@ -119,7 +154,16 @@ ? reg_info->name : ""); - RegSetKind set = GPRegSet; + 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", + reg_info->name); + return error; + } + + RegSetKind set = opt_set.getValue(); error = ReadRegisterSet(set); if (error.Fail()) return error; @@ -139,6 +183,10 @@ if (error.Fail()) return error; + error = ReadRegisterSet(FPRegSet); + if (error.Fail()) + return error; + data_sp.reset(new DataBufferHeap(m_reg_data.size(), 0)); uint8_t *dst = data_sp->GetBytes(); ::memcpy(dst, m_reg_data.data(), m_reg_data.size()); @@ -175,7 +223,11 @@ } ::memcpy(m_reg_data.data(), src, m_reg_data.size()); - return WriteRegisterSet(GPRegSet); + error = WriteRegisterSet(GPRegSet); + if (error.Fail()) + return error; + + return WriteRegisterSet(FPRegSet); } llvm::Error NativeRegisterContextFreeBSD_mips64::CopyHardwareWatchpointsFrom( diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp --- a/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp @@ -14,27 +14,53 @@ using namespace lldb_private; using namespace lldb; -static const uint32_t g_gpr_regnums[] = { - gpr_zero_mips64, gpr_r1_mips64, gpr_r2_mips64, gpr_r3_mips64, - gpr_r4_mips64, gpr_r5_mips64, gpr_r6_mips64, gpr_r7_mips64, - gpr_r8_mips64, gpr_r9_mips64, gpr_r10_mips64, gpr_r11_mips64, - gpr_r12_mips64, gpr_r13_mips64, gpr_r14_mips64, gpr_r15_mips64, - gpr_r16_mips64, gpr_r17_mips64, gpr_r18_mips64, gpr_r19_mips64, - gpr_r20_mips64, gpr_r21_mips64, gpr_r22_mips64, gpr_r23_mips64, - gpr_r24_mips64, gpr_r25_mips64, gpr_r26_mips64, gpr_r27_mips64, - gpr_gp_mips64, gpr_sp_mips64, gpr_r30_mips64, gpr_ra_mips64, - gpr_sr_mips64, gpr_mullo_mips64, gpr_mulhi_mips64, gpr_badvaddr_mips64, - gpr_cause_mips64, gpr_pc_mips64, gpr_ic_mips64, gpr_dummy_mips64}; +static const uint32_t g_gp_regnums_mips64[] = { + gpr_zero_mips64, gpr_r1_mips64, gpr_r2_mips64, gpr_r3_mips64, + gpr_r4_mips64, gpr_r5_mips64, gpr_r6_mips64, gpr_r7_mips64, + gpr_r8_mips64, gpr_r9_mips64, gpr_r10_mips64, gpr_r11_mips64, + gpr_r12_mips64, gpr_r13_mips64, gpr_r14_mips64, gpr_r15_mips64, + gpr_r16_mips64, gpr_r17_mips64, gpr_r18_mips64, gpr_r19_mips64, + gpr_r20_mips64, gpr_r21_mips64, gpr_r22_mips64, gpr_r23_mips64, + gpr_r24_mips64, gpr_r25_mips64, gpr_r26_mips64, gpr_r27_mips64, + gpr_gp_mips64, gpr_sp_mips64, gpr_r30_mips64, gpr_ra_mips64, + gpr_sr_mips64, gpr_mullo_mips64, gpr_mulhi_mips64, gpr_badvaddr_mips64, + gpr_cause_mips64, gpr_pc_mips64, gpr_ic_mips64, gpr_dummy_mips64, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; + +static_assert((sizeof(g_gp_regnums_mips64) / sizeof(g_gp_regnums_mips64[0])) - + 1 == + k_num_gpr_registers_mips64, + "g_gp_regnums_mips64 has wrong number of register infos"); + +const uint32_t g_fp_regnums_mips64[] = { + fpr_f0_mips64, fpr_f1_mips64, fpr_f2_mips64, fpr_f3_mips64, + fpr_f4_mips64, fpr_f5_mips64, fpr_f6_mips64, fpr_f7_mips64, + fpr_f8_mips64, fpr_f9_mips64, fpr_f10_mips64, fpr_f11_mips64, + fpr_f12_mips64, fpr_f13_mips64, fpr_f14_mips64, fpr_f15_mips64, + fpr_f16_mips64, fpr_f17_mips64, fpr_f18_mips64, fpr_f19_mips64, + fpr_f20_mips64, fpr_f21_mips64, fpr_f22_mips64, fpr_f23_mips64, + fpr_f24_mips64, fpr_f25_mips64, fpr_f26_mips64, fpr_f27_mips64, + fpr_f28_mips64, fpr_f29_mips64, fpr_f30_mips64, fpr_f31_mips64, + fpr_fcsr_mips64, fpr_fir_mips64, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; + +static_assert((sizeof(g_fp_regnums_mips64) / sizeof(g_fp_regnums_mips64[0])) - + 1 == + k_num_fpr_registers_mips64, + "g_fp_regnums_mips64 has wrong number of register infos"); // Number of register sets provided by this context. -constexpr size_t k_num_register_sets = 1; +constexpr size_t k_num_register_sets = 2; static const RegisterSet g_reg_sets_mips64[k_num_register_sets] = { {"General Purpose Registers", "gpr", k_num_gpr_registers_mips64, - g_gpr_regnums}, + g_gp_regnums_mips64}, + {"Floating Point Registers", "fpu", k_num_fpr_registers_mips64, + g_fp_regnums_mips64}, }; - // http://svnweb.freebsd.org/base/head/sys/mips/include/regnum.h typedef struct _GPR { uint64_t zero; @@ -79,6 +105,43 @@ uint64_t dummy; } GPR_freebsd_mips; +typedef struct _FPR { + uint64_t f0; + uint64_t f1; + uint64_t f2; + uint64_t f3; + uint64_t f4; + uint64_t f5; + uint64_t f6; + uint64_t f7; + uint64_t f8; + uint64_t f9; + uint64_t f10; + uint64_t f11; + uint64_t f12; + uint64_t f13; + uint64_t f14; + uint64_t f15; + uint64_t f16; + uint64_t f17; + uint64_t f18; + uint64_t f19; + uint64_t f20; + uint64_t f21; + uint64_t f22; + uint64_t f23; + uint64_t f24; + uint64_t f25; + uint64_t f26; + uint64_t f27; + uint64_t f28; + uint64_t f29; + uint64_t f30; + uint64_t f31; + uint64_t fcsr; + uint64_t fir; +} FPR_freebsd_mips; + // Include RegisterInfos_mips64 to declare our g_register_infos_mips64 // structure. #define DECLARE_REGISTER_INFOS_MIPS64_STRUCT @@ -95,14 +158,13 @@ const RegisterSet * RegisterContextFreeBSD_mips64::GetRegisterSet(size_t set) const { - // Check if RegisterSet is available - if (set < k_num_register_sets) - return &g_reg_sets_mips64[set]; - return nullptr; + // Check if RegisterSet is available + if (set < k_num_register_sets) + return &g_reg_sets_mips64[set]; + return nullptr; } -size_t -RegisterContextFreeBSD_mips64::GetRegisterSetCount() const { +size_t RegisterContextFreeBSD_mips64::GetRegisterSetCount() const { return k_num_register_sets; } diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfos_mips64.h b/lldb/source/Plugins/Process/Utility/RegisterInfos_mips64.h --- a/lldb/source/Plugins/Process/Utility/RegisterInfos_mips64.h +++ b/lldb/source/Plugins/Process/Utility/RegisterInfos_mips64.h @@ -11,12 +11,16 @@ #include "lldb/Core/dwarf.h" #include "llvm/Support/Compiler.h" - #ifdef DECLARE_REGISTER_INFOS_MIPS64_STRUCT // Computes the offset of the given GPR in the user data area. #define GPR_OFFSET(regname) (LLVM_EXTENSION offsetof(GPR_freebsd_mips, regname)) +// Computes the offset of the given FPR in the extended data area. +#define FPR_OFFSET(regname) \ + (sizeof(GPR_freebsd_mips) + \ + LLVM_EXTENSION offsetof(FPR_freebsd_mips, regname)) + // RegisterKind: EHFrame, DWARF, Generic, Process Plugin, LLDB // Note that the size and offset will be updated by platform-specific classes. @@ -29,6 +33,31 @@ NULL, NULL, NULL, 0 \ } +const uint8_t dwarf_opcode_mips64[] = { + llvm::dwarf::DW_OP_regx, dwarf_sr_mips64, llvm::dwarf::DW_OP_lit1, + llvm::dwarf::DW_OP_lit26, llvm::dwarf::DW_OP_shl, llvm::dwarf::DW_OP_and, + llvm::dwarf::DW_OP_lit26, llvm::dwarf::DW_OP_shr}; + +#define DEFINE_FPR(reg, alt, kind1, kind2, kind3) \ + { \ + #reg, alt, sizeof(((FPR_freebsd_mips *) 0)->reg), \ + FPR_OFFSET(reg), eEncodingIEEE754, eFormatFloat, \ + {kind1, kind2, kind3, LLDB_INVALID_REGNUM, \ + fpr_##reg##_mips64 }, \ + NULL, NULL, dwarf_opcode_mips64, \ + sizeof(dwarf_opcode_mips64) \ + } + +#define DEFINE_FPR_INFO(reg, alt, kind1, kind2, kind3) \ + { \ + #reg, alt, sizeof(((FPR_freebsd_mips *) 0)->reg), \ + FPR_OFFSET(reg), eEncodingUint, eFormatHex, \ + {kind1, kind2, kind3, LLDB_INVALID_REGNUM, \ + fpr_##reg##_mips64 }, \ + NULL, NULL, NULL, 0 \ + } + + static RegisterInfo g_register_infos_mips64[] = { // General purpose registers. EH_Frame, DWARF, // Generic, Process Plugin @@ -112,6 +141,75 @@ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(dummy, nullptr, dwarf_dummy_mips64, dwarf_dummy_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + + DEFINE_FPR(f0, nullptr, dwarf_f0_mips64, dwarf_f0_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f1, nullptr, dwarf_f1_mips64, dwarf_f1_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f2, nullptr, dwarf_f2_mips64, dwarf_f2_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f3, nullptr, dwarf_f3_mips64, dwarf_f3_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f4, nullptr, dwarf_f4_mips64, dwarf_f4_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f5, nullptr, dwarf_f5_mips64, dwarf_f5_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f6, nullptr, dwarf_f6_mips64, dwarf_f6_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f7, nullptr, dwarf_f7_mips64, dwarf_f7_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f8, nullptr, dwarf_f8_mips64, dwarf_f8_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f9, nullptr, dwarf_f9_mips64, dwarf_f9_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f10, nullptr, dwarf_f10_mips64, dwarf_f10_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f11, nullptr, dwarf_f11_mips64, dwarf_f11_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f12, nullptr, dwarf_f12_mips64, dwarf_f12_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f13, nullptr, dwarf_f13_mips64, dwarf_f13_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f14, nullptr, dwarf_f14_mips64, dwarf_f14_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f15, nullptr, dwarf_f15_mips64, dwarf_f15_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f16, nullptr, dwarf_f16_mips64, dwarf_f16_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f17, nullptr, dwarf_f17_mips64, dwarf_f17_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f18, nullptr, dwarf_f18_mips64, dwarf_f18_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f19, nullptr, dwarf_f19_mips64, dwarf_f19_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f20, nullptr, dwarf_f20_mips64, dwarf_f20_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f21, nullptr, dwarf_f21_mips64, dwarf_f21_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f22, nullptr, dwarf_f22_mips64, dwarf_f22_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f23, nullptr, dwarf_f23_mips64, dwarf_f23_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f24, nullptr, dwarf_f24_mips64, dwarf_f24_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f25, nullptr, dwarf_f25_mips64, dwarf_f25_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f26, nullptr, dwarf_f26_mips64, dwarf_f26_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f27, nullptr, dwarf_f27_mips64, dwarf_f27_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f28, nullptr, dwarf_f28_mips64, dwarf_f28_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f29, nullptr, dwarf_f29_mips64, dwarf_f29_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f30, nullptr, dwarf_f30_mips64, dwarf_f30_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f31, nullptr, dwarf_f31_mips64, dwarf_f31_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR_INFO(fcsr, nullptr, dwarf_fcsr_mips64, dwarf_fcsr_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR_INFO(fir, nullptr, dwarf_fir_mips64, dwarf_fir_mips64, + LLDB_INVALID_REGNUM), }; static_assert((sizeof(g_register_infos_mips64) / diff --git a/lldb/source/Plugins/Process/Utility/lldb-mips-freebsd-register-enums.h b/lldb/source/Plugins/Process/Utility/lldb-mips-freebsd-register-enums.h --- a/lldb/source/Plugins/Process/Utility/lldb-mips-freebsd-register-enums.h +++ b/lldb/source/Plugins/Process/Utility/lldb-mips-freebsd-register-enums.h @@ -57,9 +57,47 @@ gpr_dummy_mips64, k_last_gpr_mips64 = gpr_dummy_mips64, + k_first_fpr_mips64, + fpr_f0_mips64 = k_first_fpr_mips64, + fpr_f1_mips64, + fpr_f2_mips64, + fpr_f3_mips64, + fpr_f4_mips64, + fpr_f5_mips64, + fpr_f6_mips64, + fpr_f7_mips64, + fpr_f8_mips64, + fpr_f9_mips64, + fpr_f10_mips64, + fpr_f11_mips64, + fpr_f12_mips64, + fpr_f13_mips64, + fpr_f14_mips64, + fpr_f15_mips64, + fpr_f16_mips64, + fpr_f17_mips64, + fpr_f18_mips64, + fpr_f19_mips64, + fpr_f20_mips64, + fpr_f21_mips64, + fpr_f22_mips64, + fpr_f23_mips64, + fpr_f24_mips64, + fpr_f25_mips64, + fpr_f26_mips64, + fpr_f27_mips64, + fpr_f28_mips64, + fpr_f29_mips64, + fpr_f30_mips64, + fpr_f31_mips64, + fpr_fcsr_mips64, + fpr_fir_mips64, + k_last_fpr_mips64 = fpr_fir_mips64, + k_num_registers_mips64, - k_num_gpr_registers_mips64 = k_last_gpr_mips64 - k_first_gpr_mips64 + 1 + k_num_gpr_registers_mips64 = k_last_gpr_mips64 - k_first_gpr_mips64 + 1, + k_num_fpr_registers_mips64 = k_last_fpr_mips64 - k_first_fpr_mips64 + 1, }; -} +} // namespace lldb_private #endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_MIPS_FREEBSD_REGISTER_ENUMS_H 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 @@ -409,6 +409,11 @@ EXPECT_THAT(GetRegParams(reg_ctx, gpr_##lldb_reg##_mips64), \ ::testing::Pair(offsetof(reg, r_regs[fbsd_regno]), \ sizeof(reg::r_regs[fbsd_regno]))) +#define EXPECT_FPU_MIPS64(lldb_reg, fbsd_regno) \ + EXPECT_THAT( \ + GetRegParams(reg_ctx, fpr_##lldb_reg##_mips64), \ + ::testing::Pair(offsetof(fpreg, r_regs[fbsd_regno]) + base_offset, \ + sizeof(fpreg::r_regs[fbsd_regno]))) TEST(RegisterContextFreeBSDTest, mips64) { ArchSpec arch{"mips64-unknown-freebsd"}; @@ -457,6 +462,10 @@ EXPECT_GPR_MIPS64(pc, 37); EXPECT_GPR_MIPS64(ic, 38); EXPECT_GPR_MIPS64(dummy, 39); + + size_t base_offset = reg_ctx.GetRegisterInfo()[fpr_f0_mips64].byte_offset; + + EXPECT_FPU_MIPS64(f0, 0); } #endif // defined(__mips64__)