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