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 ®_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 ®_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