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 &reg_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 &reg_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