LLDB mainline
NativeRegisterContextLinux_loongarch64.cpp
Go to the documentation of this file.
1//===-- NativeRegisterContextLinux_loongarch64.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(__loongarch__) && __loongarch_grlen == 64
10
12
13#include "lldb/Host/HostInfo.h"
15#include "lldb/Utility/Log.h"
17#include "lldb/Utility/Status.h"
18
23
24// NT_PRSTATUS and NT_FPREGSET definition
25#include <elf.h>
26// struct iovec definition
27#include <sys/uio.h>
28
29#define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize())
30
31using namespace lldb;
32using namespace lldb_private;
33using namespace lldb_private::process_linux;
34
35std::unique_ptr<NativeRegisterContextLinux>
36NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
37 const ArchSpec &target_arch, NativeThreadLinux &native_thread) {
38 switch (target_arch.GetMachine()) {
39 case llvm::Triple::loongarch64: {
40 Flags opt_regsets;
41 auto register_info_up = std::make_unique<RegisterInfoPOSIX_loongarch64>(
42 target_arch, opt_regsets);
43 return std::make_unique<NativeRegisterContextLinux_loongarch64>(
44 target_arch, native_thread, std::move(register_info_up));
45 }
46 default:
47 llvm_unreachable("have no register context for architecture");
48 }
49}
50
51llvm::Expected<ArchSpec>
52NativeRegisterContextLinux::DetermineArchitecture(lldb::tid_t tid) {
53 return HostInfo::GetArchitecture();
54}
55
56NativeRegisterContextLinux_loongarch64::NativeRegisterContextLinux_loongarch64(
57 const ArchSpec &target_arch, NativeThreadProtocol &native_thread,
58 std::unique_ptr<RegisterInfoPOSIX_loongarch64> register_info_up)
60 register_info_up.release()),
61 NativeRegisterContextLinux(native_thread) {
62 ::memset(&m_fpr, 0, sizeof(m_fpr));
63 ::memset(&m_gpr, 0, sizeof(m_gpr));
64
65 m_gpr_is_valid = false;
66 m_fpu_is_valid = false;
67}
68
70NativeRegisterContextLinux_loongarch64::GetRegisterInfo() const {
71 return static_cast<const RegisterInfoPOSIX_loongarch64 &>(
72 NativeRegisterContextRegisterInfo::GetRegisterInfoInterface());
73}
74
75uint32_t NativeRegisterContextLinux_loongarch64::GetRegisterSetCount() const {
76 return GetRegisterInfo().GetRegisterSetCount();
77}
78
79const RegisterSet *NativeRegisterContextLinux_loongarch64::GetRegisterSet(
80 uint32_t set_index) const {
81 return GetRegisterInfo().GetRegisterSet(set_index);
82}
83
84uint32_t NativeRegisterContextLinux_loongarch64::GetUserRegisterCount() const {
85 uint32_t count = 0;
86 for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index)
87 count += GetRegisterSet(set_index)->num_registers;
88 return count;
89}
90
91Status NativeRegisterContextLinux_loongarch64::ReadRegister(
92 const RegisterInfo *reg_info, RegisterValue &reg_value) {
94
95 if (!reg_info) {
96 error.SetErrorString("reg_info NULL");
97 return error;
98 }
99
100 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
101
102 if (reg == LLDB_INVALID_REGNUM)
103 return Status("no lldb regnum for %s", reg_info && reg_info->name
104 ? reg_info->name
105 : "<unknown register>");
106
107 uint8_t *src = nullptr;
108 uint32_t offset = LLDB_INVALID_INDEX32;
109
110 if (IsGPR(reg)) {
111 error = ReadGPR();
112 if (error.Fail())
113 return error;
114
115 offset = reg_info->byte_offset;
116 assert(offset < GetGPRSize());
117 src = (uint8_t *)GetGPRBuffer() + offset;
118
119 } else if (IsFPR(reg)) {
120 error = ReadFPR();
121 if (error.Fail())
122 return error;
123
124 offset = CalculateFprOffset(reg_info);
125 assert(offset < GetFPRSize());
126 src = (uint8_t *)GetFPRBuffer() + offset;
127 } else
128 return Status("failed - register wasn't recognized to be a GPR or an FPR, "
129 "write strategy unknown");
130
131 reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size,
132 eByteOrderLittle, error);
133
134 return error;
135}
136
137Status NativeRegisterContextLinux_loongarch64::WriteRegister(
138 const RegisterInfo *reg_info, const RegisterValue &reg_value) {
140
141 if (!reg_info)
142 return Status("reg_info NULL");
143
144 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
145
146 if (reg == LLDB_INVALID_REGNUM)
147 return Status("no lldb regnum for %s", reg_info->name != nullptr
148 ? reg_info->name
149 : "<unknown register>");
150
151 uint8_t *dst = nullptr;
152 uint32_t offset = LLDB_INVALID_INDEX32;
153
154 if (IsGPR(reg)) {
155 error = ReadGPR();
156 if (error.Fail())
157 return error;
158
159 assert(reg_info->byte_offset < GetGPRSize());
160 dst = (uint8_t *)GetGPRBuffer() + reg_info->byte_offset;
161 ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size);
162
163 return WriteGPR();
164 } else if (IsFPR(reg)) {
165 error = ReadFPR();
166 if (error.Fail())
167 return error;
168
169 offset = CalculateFprOffset(reg_info);
170 assert(offset < GetFPRSize());
171 dst = (uint8_t *)GetFPRBuffer() + offset;
172 ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size);
173
174 return WriteFPR();
175 }
176
177 return Status("Failed to write register value");
178}
179
180Status NativeRegisterContextLinux_loongarch64::ReadAllRegisterValues(
183
184 data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
185
186 error = ReadGPR();
187 if (error.Fail())
188 return error;
189
190 error = ReadFPR();
191 if (error.Fail())
192 return error;
193
194 uint8_t *dst = data_sp->GetBytes();
195 ::memcpy(dst, GetGPRBuffer(), GetGPRSize());
196 dst += GetGPRSize();
197 ::memcpy(dst, GetFPRBuffer(), GetFPRSize());
198
199 return error;
200}
201
202Status NativeRegisterContextLinux_loongarch64::WriteAllRegisterValues(
203 const lldb::DataBufferSP &data_sp) {
205
206 if (!data_sp) {
207 error.SetErrorStringWithFormat(
208 "NativeRegisterContextLinux_loongarch64::%s invalid data_sp provided",
209 __FUNCTION__);
210 return error;
211 }
212
213 if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
214 error.SetErrorStringWithFormat(
215 "NativeRegisterContextLinux_loongarch64::%s data_sp contained "
216 "mismatched data size, expected %" PRIu64 ", actual %" PRIu64,
217 __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
218 return error;
219 }
220
221 const uint8_t *src = data_sp->GetBytes();
222 if (src == nullptr) {
223 error.SetErrorStringWithFormat("NativeRegisterContextLinux_loongarch64::%s "
224 "DataBuffer::GetBytes() returned a null "
225 "pointer",
226 __FUNCTION__);
227 return error;
228 }
229 ::memcpy(GetGPRBuffer(), src, GetRegisterInfoInterface().GetGPRSize());
230
231 error = WriteGPR();
232 if (error.Fail())
233 return error;
234
235 src += GetRegisterInfoInterface().GetGPRSize();
236 ::memcpy(GetFPRBuffer(), src, GetFPRSize());
237
238 error = WriteFPR();
239 if (error.Fail())
240 return error;
241
242 return error;
243}
244
245bool NativeRegisterContextLinux_loongarch64::IsGPR(unsigned reg) const {
246 return GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
248}
249
250bool NativeRegisterContextLinux_loongarch64::IsFPR(unsigned reg) const {
251 return GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
253}
254
255Status NativeRegisterContextLinux_loongarch64::ReadGPR() {
257
258 if (m_gpr_is_valid)
259 return error;
260
261 struct iovec ioVec;
262 ioVec.iov_base = GetGPRBuffer();
263 ioVec.iov_len = GetGPRSize();
264
265 error = ReadRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS);
266
267 if (error.Success())
268 m_gpr_is_valid = true;
269
270 return error;
271}
272
273Status NativeRegisterContextLinux_loongarch64::WriteGPR() {
274 Status error = ReadGPR();
275 if (error.Fail())
276 return error;
277
278 struct iovec ioVec;
279 ioVec.iov_base = GetGPRBuffer();
280 ioVec.iov_len = GetGPRSize();
281
282 m_gpr_is_valid = false;
283
284 return WriteRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS);
285}
286
287Status NativeRegisterContextLinux_loongarch64::ReadFPR() {
289
290 if (m_fpu_is_valid)
291 return error;
292
293 struct iovec ioVec;
294 ioVec.iov_base = GetFPRBuffer();
295 ioVec.iov_len = GetFPRSize();
296
297 error = ReadRegisterSet(&ioVec, GetFPRSize(), NT_FPREGSET);
298
299 if (error.Success())
300 m_fpu_is_valid = true;
301
302 return error;
303}
304
305Status NativeRegisterContextLinux_loongarch64::WriteFPR() {
306 Status error = ReadFPR();
307 if (error.Fail())
308 return error;
309
310 struct iovec ioVec;
311 ioVec.iov_base = GetFPRBuffer();
312 ioVec.iov_len = GetFPRSize();
313
314 m_fpu_is_valid = false;
315
316 return WriteRegisterSet(&ioVec, GetFPRSize(), NT_FPREGSET);
317}
318
319void NativeRegisterContextLinux_loongarch64::InvalidateAllRegisters() {
320 m_gpr_is_valid = false;
321 m_fpu_is_valid = false;
322}
323
324uint32_t NativeRegisterContextLinux_loongarch64::CalculateFprOffset(
325 const RegisterInfo *reg_info) const {
326 return reg_info->byte_offset - GetGPRSize();
327}
328
329std::vector<uint32_t>
330NativeRegisterContextLinux_loongarch64::GetExpeditedRegisters(
331 ExpeditedRegs expType) const {
332 std::vector<uint32_t> expedited_reg_nums =
333 NativeRegisterContext::GetExpeditedRegisters(expType);
334
335 return expedited_reg_nums;
336}
337
338#endif // defined(__loongarch__) && __loongarch_grlen == 64
static llvm::raw_ostream & error(Stream &strm)
#define REG_CONTEXT_SIZE
An architecture specification class.
Definition: ArchSpec.h:31
llvm::Triple::ArchType GetMachine() const
Returns a machine family for the current architecture.
Definition: ArchSpec.cpp:697
A subclass of DataBuffer that stores a data buffer on the heap.
A class to manage flags.
Definition: Flags.h:22
uint32_t SetFromMemoryData(const RegisterInfo &reg_info, const void *src, uint32_t src_len, lldb::ByteOrder src_byte_order, Status &error)
const void * GetBytes() const
An error handling class.
Definition: Status.h:44
#define LLDB_INVALID_INDEX32
Definition: lldb-defines.h:83
#define LLDB_INVALID_REGNUM
Definition: lldb-defines.h:87
A class that represents a running process on the host machine.
Definition: SBAddress.h:15
std::shared_ptr< lldb_private::DataBuffer > DataBufferSP
Definition: lldb-forward.h:334
std::shared_ptr< lldb_private::WritableDataBuffer > WritableDataBufferSP
Definition: lldb-forward.h:335
uint64_t tid_t
Definition: lldb-types.h:84
@ eRegisterKindLLDB
lldb's internal register numbers
Every register is described in detail including its name, alternate name (optional),...
uint32_t byte_offset
The byte offset in the register context data where this register's value is found.
uint32_t byte_size
Size in bytes of the register.
uint32_t kinds[lldb::kNumRegisterKinds]
Holds all of the various register numbers for all register kinds.
const char * name
Name of this register, can't be NULL.
Registers are grouped into register sets.
size_t num_registers
The number of registers in REGISTERS array below.