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