1 //===-- NativeRegisterContextFreeBSD_mips64.cpp ---------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #if defined(__mips64__) 10 11 #include "NativeRegisterContextFreeBSD_mips64.h" 12 13 #include "lldb/Utility/DataBufferHeap.h" 14 #include "lldb/Utility/RegisterValue.h" 15 #include "lldb/Utility/Status.h" 16 17 #include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h" 18 #include "Plugins/Process/Utility/lldb-mips-freebsd-register-enums.h" 19 20 // clang-format off 21 #include <sys/param.h> 22 #include <sys/ptrace.h> 23 #include <sys/types.h> 24 // clang-format on 25 #include <optional> 26 27 using namespace lldb; 28 using namespace lldb_private; 29 using namespace lldb_private::process_freebsd; 30 31 NativeRegisterContextFreeBSD * 32 NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD( 33 const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { 34 return new NativeRegisterContextFreeBSD_mips64(target_arch, native_thread); 35 } 36 37 NativeRegisterContextFreeBSD_mips64::NativeRegisterContextFreeBSD_mips64( 38 const ArchSpec &target_arch, NativeThreadProtocol &native_thread) 39 : NativeRegisterContextRegisterInfo( 40 native_thread, new RegisterContextFreeBSD_mips64(target_arch)) {} 41 42 RegisterContextFreeBSD_mips64 & 43 NativeRegisterContextFreeBSD_mips64::GetRegisterInfo() const { 44 return static_cast<RegisterContextFreeBSD_mips64 &>( 45 *m_register_info_interface_up); 46 } 47 48 uint32_t NativeRegisterContextFreeBSD_mips64::GetRegisterSetCount() const { 49 return GetRegisterInfo().GetRegisterSetCount(); 50 } 51 52 const RegisterSet * 53 NativeRegisterContextFreeBSD_mips64::GetRegisterSet(uint32_t set_index) const { 54 return GetRegisterInfo().GetRegisterSet(set_index); 55 } 56 57 uint32_t NativeRegisterContextFreeBSD_mips64::GetUserRegisterCount() const { 58 uint32_t count = 0; 59 for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index) 60 count += GetRegisterSet(set_index)->num_registers; 61 return count; 62 } 63 64 std::optional<NativeRegisterContextFreeBSD_mips64::RegSetKind> 65 NativeRegisterContextFreeBSD_mips64::GetSetForNativeRegNum( 66 uint32_t reg_num) const { 67 switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { 68 case llvm::Triple::mips64: 69 if (reg_num >= k_first_gpr_mips64 && reg_num <= k_last_gpr_mips64) 70 return GPRegSet; 71 if (reg_num >= k_first_fpr_mips64 && reg_num <= k_last_fpr_mips64) 72 return FPRegSet; 73 break; 74 default: 75 llvm_unreachable("Unhandled target architecture."); 76 } 77 78 llvm_unreachable("Register does not belong to any register set"); 79 } 80 81 Status NativeRegisterContextFreeBSD_mips64::ReadRegisterSet(RegSetKind set) { 82 switch (set) { 83 case GPRegSet: 84 return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(), 85 m_reg_data.data()); 86 case FPRegSet: 87 return NativeProcessFreeBSD::PtraceWrapper( 88 PT_GETFPREGS, m_thread.GetID(), 89 m_reg_data.data() + GetRegisterInfo().GetGPRSize()); 90 } 91 llvm_unreachable("NativeRegisterContextFreeBSD_mips64::ReadRegisterSet"); 92 } 93 94 Status NativeRegisterContextFreeBSD_mips64::WriteRegisterSet(RegSetKind set) { 95 switch (set) { 96 case GPRegSet: 97 return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(), 98 m_reg_data.data()); 99 case FPRegSet: 100 return NativeProcessFreeBSD::PtraceWrapper( 101 PT_SETFPREGS, m_thread.GetID(), 102 m_reg_data.data() + GetRegisterInfo().GetGPRSize()); 103 } 104 llvm_unreachable("NativeRegisterContextFreeBSD_mips64::WriteRegisterSet"); 105 } 106 107 Status 108 NativeRegisterContextFreeBSD_mips64::ReadRegister(const RegisterInfo *reg_info, 109 RegisterValue ®_value) { 110 Status error; 111 112 if (!reg_info) { 113 error.SetErrorString("reg_info NULL"); 114 return error; 115 } 116 117 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 118 119 if (reg == LLDB_INVALID_REGNUM) 120 return Status("no lldb regnum for %s", reg_info && reg_info->name 121 ? reg_info->name 122 : "<unknown register>"); 123 124 std::optional<RegSetKind> opt_set = GetSetForNativeRegNum(reg); 125 if (!opt_set) { 126 // This is likely an internal register for lldb use only and should not be 127 // directly queried. 128 error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set", 129 reg_info->name); 130 return error; 131 } 132 133 RegSetKind set = *opt_set; 134 error = ReadRegisterSet(set); 135 if (error.Fail()) 136 return error; 137 138 assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size()); 139 reg_value.SetBytes(m_reg_data.data() + reg_info->byte_offset, 140 reg_info->byte_size, endian::InlHostByteOrder()); 141 return error; 142 } 143 144 Status NativeRegisterContextFreeBSD_mips64::WriteRegister( 145 const RegisterInfo *reg_info, const RegisterValue ®_value) { 146 Status error; 147 148 if (!reg_info) 149 return Status("reg_info NULL"); 150 151 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 152 153 if (reg == LLDB_INVALID_REGNUM) 154 return Status("no lldb regnum for %s", reg_info && reg_info->name 155 ? reg_info->name 156 : "<unknown register>"); 157 158 std::optional<RegSetKind> opt_set = GetSetForNativeRegNum(reg); 159 if (!opt_set) { 160 // This is likely an internal register for lldb use only and should not be 161 // directly queried. 162 error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set", 163 reg_info->name); 164 return error; 165 } 166 167 RegSetKind set = *opt_set; 168 error = ReadRegisterSet(set); 169 if (error.Fail()) 170 return error; 171 172 assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size()); 173 ::memcpy(m_reg_data.data() + reg_info->byte_offset, reg_value.GetBytes(), 174 reg_info->byte_size); 175 176 return WriteRegisterSet(set); 177 } 178 179 Status NativeRegisterContextFreeBSD_mips64::ReadAllRegisterValues( 180 lldb::WritableDataBufferSP &data_sp) { 181 Status error; 182 183 error = ReadRegisterSet(GPRegSet); 184 if (error.Fail()) 185 return error; 186 187 error = ReadRegisterSet(FPRegSet); 188 if (error.Fail()) 189 return error; 190 191 data_sp.reset(new DataBufferHeap(m_reg_data.size(), 0)); 192 uint8_t *dst = data_sp->GetBytes(); 193 ::memcpy(dst, m_reg_data.data(), m_reg_data.size()); 194 195 return error; 196 } 197 198 Status NativeRegisterContextFreeBSD_mips64::WriteAllRegisterValues( 199 const lldb::DataBufferSP &data_sp) { 200 Status error; 201 202 if (!data_sp) { 203 error.SetErrorStringWithFormat( 204 "NativeRegisterContextFreeBSD_mips64::%s invalid data_sp provided", 205 __FUNCTION__); 206 return error; 207 } 208 209 if (data_sp->GetByteSize() != m_reg_data.size()) { 210 error.SetErrorStringWithFormat( 211 "NativeRegisterContextFreeBSD_mips64::%s data_sp contained mismatched " 212 "data size, expected %" PRIu64 ", actual %" PRIu64, 213 __FUNCTION__, m_reg_data.size(), data_sp->GetByteSize()); 214 return error; 215 } 216 217 const uint8_t *src = data_sp->GetBytes(); 218 if (src == nullptr) { 219 error.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_mips64::%s " 220 "DataBuffer::GetBytes() returned a null " 221 "pointer", 222 __FUNCTION__); 223 return error; 224 } 225 ::memcpy(m_reg_data.data(), src, m_reg_data.size()); 226 227 error = WriteRegisterSet(GPRegSet); 228 if (error.Fail()) 229 return error; 230 231 return WriteRegisterSet(FPRegSet); 232 } 233 234 llvm::Error NativeRegisterContextFreeBSD_mips64::CopyHardwareWatchpointsFrom( 235 NativeRegisterContextFreeBSD &source) { 236 return llvm::Error::success(); 237 } 238 239 #endif // defined (__mips64__) 240