xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_riscv64.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1 //===-- NativeRegisterContextLinux_riscv64.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(__riscv) && __riscv_xlen == 64
10 
11 #include "NativeRegisterContextLinux_riscv64.h"
12 
13 #include "lldb/Host/HostInfo.h"
14 #include "lldb/Utility/DataBufferHeap.h"
15 #include "lldb/Utility/Log.h"
16 #include "lldb/Utility/RegisterValue.h"
17 #include "lldb/Utility/Status.h"
18 
19 #include "Plugins/Process/Linux/NativeProcessLinux.h"
20 #include "Plugins/Process/Linux/Procfs.h"
21 #include "Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.h"
22 #include "Plugins/Process/Utility/lldb-riscv-register-enums.h"
23 
24 // System includes - They have to be included after framework includes because
25 // they define some macros which collide with variable names in other modules
26 #include <sys/uio.h>
27 // NT_PRSTATUS and NT_FPREGSET definition
28 #include <elf.h>
29 
30 #define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize())
31 
32 using namespace lldb;
33 using namespace lldb_private;
34 using namespace lldb_private::process_linux;
35 
36 std::unique_ptr<NativeRegisterContextLinux>
CreateHostNativeRegisterContextLinux(const ArchSpec & target_arch,NativeThreadLinux & native_thread)37 NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
38     const ArchSpec &target_arch, NativeThreadLinux &native_thread) {
39   switch (target_arch.GetMachine()) {
40   case llvm::Triple::riscv64: {
41     Flags opt_regsets;
42     auto register_info_up =
43         std::make_unique<RegisterInfoPOSIX_riscv64>(target_arch, opt_regsets);
44     return std::make_unique<NativeRegisterContextLinux_riscv64>(
45         target_arch, native_thread, std::move(register_info_up));
46   }
47   default:
48     llvm_unreachable("have no register context for architecture");
49   }
50 }
51 
52 llvm::Expected<ArchSpec>
DetermineArchitecture(lldb::tid_t tid)53 NativeRegisterContextLinux::DetermineArchitecture(lldb::tid_t tid) {
54   return HostInfo::GetArchitecture();
55 }
56 
NativeRegisterContextLinux_riscv64(const ArchSpec & target_arch,NativeThreadProtocol & native_thread,std::unique_ptr<RegisterInfoPOSIX_riscv64> register_info_up)57 NativeRegisterContextLinux_riscv64::NativeRegisterContextLinux_riscv64(
58     const ArchSpec &target_arch, NativeThreadProtocol &native_thread,
59     std::unique_ptr<RegisterInfoPOSIX_riscv64> register_info_up)
60     : NativeRegisterContextRegisterInfo(native_thread,
61                                         register_info_up.release()),
62       NativeRegisterContextLinux(native_thread) {
63   ::memset(&m_fpr, 0, sizeof(m_fpr));
64   ::memset(&m_gpr, 0, sizeof(m_gpr));
65 
66   m_gpr_is_valid = false;
67   m_fpu_is_valid = false;
68 }
69 
70 const RegisterInfoPOSIX_riscv64 &
GetRegisterInfo() const71 NativeRegisterContextLinux_riscv64::GetRegisterInfo() const {
72   return static_cast<const RegisterInfoPOSIX_riscv64 &>(
73       NativeRegisterContextRegisterInfo::GetRegisterInfoInterface());
74 }
75 
GetRegisterSetCount() const76 uint32_t NativeRegisterContextLinux_riscv64::GetRegisterSetCount() const {
77   return GetRegisterInfo().GetRegisterSetCount();
78 }
79 
80 const RegisterSet *
GetRegisterSet(uint32_t set_index) const81 NativeRegisterContextLinux_riscv64::GetRegisterSet(uint32_t set_index) const {
82   return GetRegisterInfo().GetRegisterSet(set_index);
83 }
84 
GetUserRegisterCount() const85 uint32_t NativeRegisterContextLinux_riscv64::GetUserRegisterCount() const {
86   uint32_t count = 0;
87   for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index)
88     count += GetRegisterSet(set_index)->num_registers;
89   return count;
90 }
91 
92 Status
ReadRegister(const RegisterInfo * reg_info,RegisterValue & reg_value)93 NativeRegisterContextLinux_riscv64::ReadRegister(const RegisterInfo *reg_info,
94                                                  RegisterValue &reg_value) {
95   Status error;
96 
97   if (!reg_info) {
98     error.SetErrorString("reg_info NULL");
99     return error;
100   }
101 
102   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
103 
104   if (reg == LLDB_INVALID_REGNUM)
105     return Status("no lldb regnum for %s", reg_info && reg_info->name
106                                                ? reg_info->name
107                                                : "<unknown register>");
108 
109   if (reg == gpr_x0_riscv) {
110     reg_value.SetUInt(0, reg_info->byte_size);
111     return error;
112   }
113 
114   uint8_t *src = nullptr;
115   uint32_t offset = LLDB_INVALID_INDEX32;
116 
117   if (IsGPR(reg)) {
118     error = ReadGPR();
119     if (error.Fail())
120       return error;
121 
122     offset = reg_info->byte_offset;
123     assert(offset < GetGPRSize());
124     src = (uint8_t *)GetGPRBuffer() + offset;
125 
126   } else if (IsFPR(reg)) {
127     error = ReadFPR();
128     if (error.Fail())
129       return error;
130 
131     offset = CalculateFprOffset(reg_info);
132     assert(offset < GetFPRSize());
133     src = (uint8_t *)GetFPRBuffer() + offset;
134   } else
135     return Status("failed - register wasn't recognized to be a GPR or an FPR, "
136                   "write strategy unknown");
137 
138   reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size,
139                               eByteOrderLittle, error);
140 
141   return error;
142 }
143 
WriteRegister(const RegisterInfo * reg_info,const RegisterValue & reg_value)144 Status NativeRegisterContextLinux_riscv64::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->name != nullptr
155                                                ? reg_info->name
156                                                : "<unknown register>");
157 
158   if (reg == gpr_x0_riscv) {
159     // do nothing.
160     return error;
161   }
162 
163   uint8_t *dst = nullptr;
164   uint32_t offset = LLDB_INVALID_INDEX32;
165 
166   if (IsGPR(reg)) {
167     error = ReadGPR();
168     if (error.Fail())
169       return error;
170 
171     assert(reg_info->byte_offset < GetGPRSize());
172     dst = (uint8_t *)GetGPRBuffer() + reg_info->byte_offset;
173     ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size);
174 
175     return WriteGPR();
176   } else if (IsFPR(reg)) {
177     error = ReadFPR();
178     if (error.Fail())
179       return error;
180 
181     offset = CalculateFprOffset(reg_info);
182     assert(offset < GetFPRSize());
183     dst = (uint8_t *)GetFPRBuffer() + offset;
184     ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size);
185 
186     return WriteFPR();
187   }
188 
189   return Status("Failed to write register value");
190 }
191 
ReadAllRegisterValues(lldb::WritableDataBufferSP & data_sp)192 Status NativeRegisterContextLinux_riscv64::ReadAllRegisterValues(
193     lldb::WritableDataBufferSP &data_sp) {
194   Status error;
195 
196   data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
197 
198   error = ReadGPR();
199   if (error.Fail())
200     return error;
201 
202   error = ReadFPR();
203   if (error.Fail())
204     return error;
205 
206   uint8_t *dst = const_cast<uint8_t *>(data_sp->GetBytes());
207   ::memcpy(dst, GetGPRBuffer(), GetGPRSize());
208   dst += GetGPRSize();
209   ::memcpy(dst, GetFPRBuffer(), GetFPRSize());
210 
211   return error;
212 }
213 
WriteAllRegisterValues(const lldb::DataBufferSP & data_sp)214 Status NativeRegisterContextLinux_riscv64::WriteAllRegisterValues(
215     const lldb::DataBufferSP &data_sp) {
216   Status error;
217 
218   if (!data_sp) {
219     error.SetErrorStringWithFormat(
220         "NativeRegisterContextLinux_riscv64::%s invalid data_sp provided",
221         __FUNCTION__);
222     return error;
223   }
224 
225   if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
226     error.SetErrorStringWithFormat(
227         "NativeRegisterContextLinux_riscv64::%s data_sp contained mismatched "
228         "data size, expected %" PRIu64 ", actual %" PRIu64,
229         __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
230     return error;
231   }
232 
233   uint8_t *src = const_cast<uint8_t *>(data_sp->GetBytes());
234   if (src == nullptr) {
235     error.SetErrorStringWithFormat("NativeRegisterContextLinux_riscv64::%s "
236                                    "DataBuffer::GetBytes() returned a null "
237                                    "pointer",
238                                    __FUNCTION__);
239     return error;
240   }
241   ::memcpy(GetGPRBuffer(), src, GetRegisterInfoInterface().GetGPRSize());
242 
243   error = WriteGPR();
244   if (error.Fail())
245     return error;
246 
247   src += GetRegisterInfoInterface().GetGPRSize();
248   ::memcpy(GetFPRBuffer(), src, GetFPRSize());
249 
250   error = WriteFPR();
251   if (error.Fail())
252     return error;
253 
254   return error;
255 }
256 
IsGPR(unsigned reg) const257 bool NativeRegisterContextLinux_riscv64::IsGPR(unsigned reg) const {
258   return GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
259          RegisterInfoPOSIX_riscv64::GPRegSet;
260 }
261 
IsFPR(unsigned reg) const262 bool NativeRegisterContextLinux_riscv64::IsFPR(unsigned reg) const {
263   return GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
264          RegisterInfoPOSIX_riscv64::FPRegSet;
265 }
266 
ReadGPR()267 Status NativeRegisterContextLinux_riscv64::ReadGPR() {
268   Status error;
269 
270   if (m_gpr_is_valid)
271     return error;
272 
273   struct iovec ioVec;
274   ioVec.iov_base = GetGPRBuffer();
275   ioVec.iov_len = GetGPRSize();
276 
277   error = ReadRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS);
278 
279   if (error.Success())
280     m_gpr_is_valid = true;
281 
282   return error;
283 }
284 
WriteGPR()285 Status NativeRegisterContextLinux_riscv64::WriteGPR() {
286   Status error = ReadGPR();
287   if (error.Fail())
288     return error;
289 
290   struct iovec ioVec;
291   ioVec.iov_base = GetGPRBuffer();
292   ioVec.iov_len = GetGPRSize();
293 
294   m_gpr_is_valid = false;
295 
296   return WriteRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS);
297 }
298 
ReadFPR()299 Status NativeRegisterContextLinux_riscv64::ReadFPR() {
300   Status error;
301 
302   if (m_fpu_is_valid)
303     return error;
304 
305   struct iovec ioVec;
306   ioVec.iov_base = GetFPRBuffer();
307   ioVec.iov_len = GetFPRSize();
308 
309   error = ReadRegisterSet(&ioVec, GetFPRSize(), NT_FPREGSET);
310 
311   if (error.Success())
312     m_fpu_is_valid = true;
313 
314   return error;
315 }
316 
WriteFPR()317 Status NativeRegisterContextLinux_riscv64::WriteFPR() {
318   Status error = ReadFPR();
319   if (error.Fail())
320     return error;
321 
322   struct iovec ioVec;
323   ioVec.iov_base = GetFPRBuffer();
324   ioVec.iov_len = GetFPRSize();
325 
326   m_fpu_is_valid = false;
327 
328   return WriteRegisterSet(&ioVec, GetFPRSize(), NT_FPREGSET);
329 }
330 
InvalidateAllRegisters()331 void NativeRegisterContextLinux_riscv64::InvalidateAllRegisters() {
332   m_gpr_is_valid = false;
333   m_fpu_is_valid = false;
334 }
335 
CalculateFprOffset(const RegisterInfo * reg_info) const336 uint32_t NativeRegisterContextLinux_riscv64::CalculateFprOffset(
337     const RegisterInfo *reg_info) const {
338   return reg_info->byte_offset - GetGPRSize();
339 }
340 
GetExpeditedRegisters(ExpeditedRegs expType) const341 std::vector<uint32_t> NativeRegisterContextLinux_riscv64::GetExpeditedRegisters(
342     ExpeditedRegs expType) const {
343   std::vector<uint32_t> expedited_reg_nums =
344       NativeRegisterContext::GetExpeditedRegisters(expType);
345 
346   return expedited_reg_nums;
347 }
348 
349 #endif // defined (__riscv) && __riscv_xlen == 64
350