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