LLDB mainline
RegisterContextPOSIXCore_riscv32.cpp
Go to the documentation of this file.
1//===-- RegisterContextPOSIXCore_riscv32.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
10
11#include "lldb/Core/Debugger.h"
12#include "lldb/Core/Module.h"
14#include "llvm/ADT/ArrayRef.h"
15#include "llvm/ADT/SmallVector.h"
16#include "llvm/ADT/StringRef.h"
17#include "llvm/TargetParser/SubtargetFeature.h"
18
19#define GPR_OFFSET(idx) ((idx) * sizeof(uint32_t))
20#define FPR_OFFSET(idx) ((idx) * sizeof(uint32_t))
21
22#define DECLARE_REGISTER_INFOS_RISCV32_STRUCT
24#undef DECLARE_REGISTER_INFOS_RISCV32_STRUCT
25
26using namespace lldb_private;
27
28static std::vector<uint32_t> CopyRegisterListToVector(const uint32_t *regs) {
29 if (!regs)
30 return {};
31
32 const uint32_t *end = regs;
33 while (*end != LLDB_INVALID_REGNUM)
34 ++end;
35
36 return std::vector<uint32_t>(regs, end);
37}
38
39std::unique_ptr<RegisterContextCorePOSIX_riscv32>
41 const DataExtractor &gpregset,
42 llvm::ArrayRef<CoreNote> notes) {
43 return std::unique_ptr<RegisterContextCorePOSIX_riscv32>(
45 thread, std::make_unique<RegisterInfoPOSIXDynamic_riscv32>(arch),
46 gpregset, notes));
47}
48
50 Thread &thread,
51 std::unique_ptr<RegisterInfoPOSIXDynamic_riscv32> register_info,
52 const DataExtractor &gpregset, llvm::ArrayRef<CoreNote> notes)
53 : RegisterContext(thread, 0), m_reg_infos_up(std::move(register_info)) {
54 // Compute the maximum register counts for GPR, FPR, and CSR.
55 constexpr uint32_t k_num_gpr_registers =
56 std::size(g_register_infos_riscv32_gpr);
58 constexpr uint32_t k_num_fpr_registers =
59 std::size(g_register_infos_riscv32_fpr);
61 llvm::SmallVector<std::string> features;
62 GetFeatures(features);
63 llvm::SmallVector<lldb_private::RegisterInfo> reg_infos_riscv32_csr;
64 m_reg_infos_up->BuildCSRegInfos(features, reg_infos_riscv32_csr);
65 uint32_t k_num_csr_registers = reg_infos_riscv32_csr.size();
66 const ArchSpec &target_arch = m_reg_infos_up->GetTargetArchitecture();
67 const llvm::Triple triple = target_arch.GetTriple();
68 const lldb::ByteOrder byte_order = target_arch.GetByteOrder();
69
70 std::vector<DynamicRegisterInfo::Register> registers;
71 uint32_t byte_offset = 0;
72
73 // Build dynamic register information for GPR.
74 const lldb_private::ConstString gpr_set("GPR");
75 m_gpregset.SetData(std::make_shared<DataBufferHeap>(gpregset.GetDataStart(),
76 gpregset.GetByteSize()));
77 if (m_gpregset.GetByteSize() >= g_register_infos_riscv32_gpr[0].byte_size) {
78 // GPR is available.
79 assert((m_gpregset.GetByteSize() /
80 g_register_infos_riscv32_gpr[0].byte_size) == k_num_gpr_registers &&
81 "GPR has the wrong number of registers!");
82 m_gpregset.SetByteOrder(gpregset.GetByteOrder());
83 for (const auto &gpr : g_register_infos_riscv32_gpr) {
84 registers.push_back(BuildDynamicRegister(gpr, gpr_set, byte_offset));
85 byte_offset += gpr.byte_size;
86 }
87 }
88
89 // Build dynamic register information for FPR.
90 const lldb_private::ConstString fpr_set("FPR");
91 m_fpregset = getRegset(notes, triple, FPR_Desc);
92 if (m_fpregset.GetByteSize() >= g_register_infos_riscv32_fpr[0].byte_size) {
93 // FPR is available.
94 assert((m_fpregset.GetByteSize() /
95 g_register_infos_riscv32_fpr[0].byte_size) == k_num_fpr_registers &&
96 "FPR has the wrong number of registers!");
97 m_fpregset.SetByteOrder(byte_order);
98 for (const auto &fpr : g_register_infos_riscv32_fpr) {
99 registers.push_back(BuildDynamicRegister(fpr, fpr_set, byte_offset));
100 byte_offset += fpr.byte_size;
101 }
102 }
103
104 // Build dynamic register information for CSR.
105 const lldb_private::ConstString csr_set("CSR");
107 if (m_csregset.GetByteSize() >=
108 (sizeof(csr_kv_t::addr) + sizeof(csr_kv_t::val))) {
109 // CSR is available.
110 m_csregset.SetByteOrder(byte_order);
111 lldb::offset_t offset = 0;
112 std::vector<uint32_t> csregset_regnums = {};
113 while (m_csregset.BytesLeft(offset)) {
114 uint32_t csr_addr = m_csregset.GetU32(&offset);
115 if (csregset_regnums.size() == k_num_csr_registers) {
117 llvm::formatv("parsed the permissible number of CSRs {0:x} but "
118 "NT_CSREGMAP has more; skipping the remaining CSRs",
120 break;
121 }
122 if (llvm::is_contained(csregset_regnums, csr_addr)) {
124 llvm::formatv("encountered a duplicate CSR while parsing "
125 "NT_CSREGMAP: {0}; skipping",
126 reg_infos_riscv32_csr[csr_addr].name));
127 } else {
128 csregset_regnums.push_back(csr_addr);
129 const RegisterInfo &csr = reg_infos_riscv32_csr[csr_addr];
130 registers.push_back(BuildDynamicRegister(csr, csr_set, byte_offset));
131 byte_offset += csr.byte_size;
132 }
133 // Consume and skip the CSR value to advance to the next entry.
134 (void)m_csregset.GetU32(&offset);
135 }
136 }
137
138 m_reg_infos_up->SetRegisterInfo(std::move(registers));
139}
140
142
144
146 return m_reg_infos_up->GetRegisterCount();
147}
148
151 if (reg < GetRegisterCount())
152 return &m_reg_infos_up->GetRegisterInfo()[static_cast<uint32_t>(reg)];
153 return nullptr;
154}
155
157 return m_reg_infos_up->GetRegisterSetCount();
158}
159
162 return m_reg_infos_up->GetRegisterSet(static_cast<uint32_t>(set));
163}
164
166 const RegisterInfo *reg_info, RegisterValue &value) {
167 const lldb_private::RegisterInfo *dyn_reg_info;
168 const uint8_t *src = nullptr;
169 if ((dyn_reg_info = m_reg_infos_up->GetRegisterInfo(reg_info->name))) {
170 lldb::offset_t offset = dyn_reg_info->byte_offset;
171 if (IsGPR(dyn_reg_info->kinds[lldb::eRegisterKindLLDB])) {
172 // clang-format off
173 //
174 // |____| |_______________|
175 // | | src -> | |
176 // | pc | <- dyn_reg_info->byte_offset = 0 | m_gpregset[0] | uint32_t
177 // |____| offset = 0 -> |_______________|
178 // | | | |
179 // | x1 | | m_gpregset[4] | uint32_t
180 // |____| |_______________|
181 // .. ..
182 // |____| |_______________|
183 // | | | |
184 // | xn | <- dyn_reg_info->byte_offset offset -> | m_gpregset[n] | uint32_t
185 // |____| |_______________|
186 // | | | |
187 // .. ..
188 //
189 // clang-format on
190 src = m_gpregset.GetDataStart();
191 } else if (IsFPR(dyn_reg_info->kinds[lldb::eRegisterKindLLDB])) {
192 // clang-format off
193 //
194 // |____|
195 // | |
196 // | pc | <- dyn_reg_info->byte_offset = 0
197 // |____|
198 // | |
199 // | x1 |
200 // |____|
201 // ..
202 // |____|
203 // | |
204 // | x0 |
205 // |____| |_______________|
206 // | | src -> | |
207 // | f0 | | m_fpregset[0] | uint32_t
208 // |____| offset = 0 -> |_______________|
209 // | | | |
210 // | f1 | | m_fpregset[4] | uint32_t
211 // |____| |_______________|
212 // .. ..
213 // |____| |_______________|
214 // | | | |
215 // | fn | <- dyn_reg_info->byte_offset offset -> | m_fpregset[n] | uint32_t
216 // |____| |_______________|
217 // | | | |
218 // .. ..
219 //
220 // clang-format on
221 src = m_fpregset.GetDataStart();
222 offset -= (g_register_infos_riscv32_gpr[0].byte_size *
223 m_reg_infos_up->GetGPRSize());
224 } else if (IsCSR(dyn_reg_info->kinds[lldb::eRegisterKindLLDB])) {
225 // clang-format off
226 //
227 // |______|
228 // | |
229 // | pc | <- dyn_reg_info->byte_offset = 0
230 // |______|
231 // | |
232 // | x1 |
233 // |______|
234 // ..
235 // |______|
236 // | |
237 // | x0 |
238 // |______|
239 // | |
240 // | f0 |
241 // |______|
242 // | |
243 // | f1 |
244 // |______|
245 // ..
246 // |______|
247 // | |
248 // | f31 |
249 // |______| |________________|
250 // | | src -> | |
251 // | | csr0::addr -> | m_csregset[00] | uint32_t
252 // | | offset = 0 -> | |
253 // | csr0 | |----------------|
254 // | | | |
255 // | | csr0::val -> | m_csregset[04] | uint32_t
256 // |______| |________________|
257 // | | | |
258 // | | csr1::addr -> | m_csregset[08] | uint32_t
259 // | | | |
260 // | csr1 | |----------------|
261 // | | | |
262 // | | csr1::val -> | m_csregset[12] | uint32_t
263 // |______| |________________|
264 // .. ..
265 // |______| |________________|
266 // | | | |
267 // | | csrn::addr -> | m_csregset[..] | uint32_t
268 // | | | |
269 // | csrn | |----------------|
270 // | | csrn::val -> | |
271 // | | | m_csregset[..] | uint32_t
272 // |______| offset -> |________________|
273 // | | | |
274 // .. ..
275 //
276 // clang-format on
277 src = m_csregset.GetDataStart();
278 offset -= ((g_register_infos_riscv32_gpr[0].byte_size *
279 m_reg_infos_up->GetGPRSize()) +
280 (g_register_infos_riscv32_fpr[0].byte_size *
281 m_reg_infos_up->GetFPRSize()));
282 offset *= 2;
283 offset += dyn_reg_info->byte_size;
284 } else {
285 return false;
286 }
287
289 value.SetFromMemoryData(*dyn_reg_info, src + offset,
290 dyn_reg_info->byte_size, lldb::eByteOrderLittle,
291 error);
292 return error.Success();
293 } else {
294 return false;
295 }
296}
297
299 const RegisterInfo *reg_info, const RegisterValue &value) {
300 return false;
301}
302
304 if (llvm::StringRef(
305 GetRegisterSet(m_reg_infos_up->GetRegisterSetFromRegisterIndex(reg))
306 ->name)
307 .equals_insensitive(llvm::StringRef("GPR")))
308 return true;
309 return false;
310}
311
313 if (llvm::StringRef(
314 GetRegisterSet(m_reg_infos_up->GetRegisterSetFromRegisterIndex(reg))
315 ->name)
316 .equals_insensitive(llvm::StringRef("FPR")))
317 return true;
318 return false;
319}
320
322 if (llvm::StringRef(
323 GetRegisterSet(m_reg_infos_up->GetRegisterSetFromRegisterIndex(reg))
324 ->name)
325 .equals_insensitive(llvm::StringRef("CSR")))
326 return true;
327 return false;
328}
329
332 const lldb_private::RegisterInfo &reg_info,
333 const lldb_private::ConstString &set_name, uint32_t byte_offset) {
337 set_name,
338 reg_info.byte_size,
339 byte_offset,
340 reg_info.encoding,
341 reg_info.format,
348 /*value_reg_offset=*/0,
349 reg_info.register_type};
350}
351
353 llvm::SmallVectorImpl<std::string> &features) const {
355 features.clear();
356
357 if (!m_thread.IsValid())
358 return;
359
360 auto process_sp = m_thread.GetProcess();
361 if (!process_sp)
362 return;
363
364 auto target = process_sp->CalculateTarget();
365 if (!target)
366 return;
367
368 auto module_sp = target->GetExecutableModule();
369 if (!module_sp)
370 return;
371
372 // ObjectFileELF::ParseRISCVAttributes should've already parsed features and
373 // stored them in the module's ArchSpec via ArchSpec::SetSubtargetFeatures.
374 std::vector<std::string> raw_features =
375 module_sp->GetArchitecture().GetSubtargetFeatures().getFeatures();
376
377 if (raw_features.empty()) {
378 LLDB_LOG(log, "no RISC-V subtarget feature found in module ArchSpec");
379 return;
380 }
381
382 features.reserve(raw_features.size());
383 for (const auto &feature : raw_features) {
384 if (feature.empty() || !llvm::SubtargetFeatures::isEnabled(feature))
385 continue;
386 auto stripped = llvm::SubtargetFeatures::StripFlag(feature);
387 if (!stripped.empty())
388 features.emplace_back(stripped);
389 }
390}
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition Log.h:375
const size_t k_num_gpr_registers
const size_t k_num_csr_registers
const size_t k_num_fpr_registers
static std::vector< uint32_t > CopyRegisterListToVector(const uint32_t *regs)
const lldb_private::RegisterInfo * GetRegisterInfoAtIndex(size_t reg) override
static std::unique_ptr< RegisterContextCorePOSIX_riscv32 > Create(lldb_private::Thread &thread, const lldb_private::ArchSpec &arch, const lldb_private::DataExtractor &gpregset, llvm::ArrayRef< lldb_private::CoreNote > notes)
const lldb_private::RegisterSet * GetRegisterSet(size_t set) override
void GetFeatures(llvm::SmallVectorImpl< std::string > &features) const
Retrieves enabled RISC-V ISA extension feature names from the module's ArchSpec.
bool WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value) override
RegisterContextCorePOSIX_riscv32(lldb_private::Thread &thread, std::unique_ptr< RegisterInfoPOSIXDynamic_riscv32 > register_info, const lldb_private::DataExtractor &gpregset, llvm::ArrayRef< lldb_private::CoreNote > notes)
bool ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value) override
std::unique_ptr< RegisterInfoPOSIXDynamic_riscv32 > m_reg_infos_up
lldb_private::DynamicRegisterInfo::Register BuildDynamicRegister(const lldb_private::RegisterInfo &reg_info, const lldb_private::ConstString &set_name, uint32_t byte_offset)
An architecture specification class.
Definition ArchSpec.h:32
llvm::Triple & GetTriple()
Architecture triple accessor.
Definition ArchSpec.h:544
lldb::ByteOrder GetByteOrder() const
Returns the byte order for the architecture specification.
Definition ArchSpec.cpp:938
A uniqued constant string class.
Definition ConstString.h:40
An data extractor class.
virtual uint64_t GetByteSize() const
Get the number of bytes contained in this object.
const uint8_t * GetDataStart() const
Get the data start pointer.
lldb::ByteOrder GetByteOrder() const
Get the current byte order value.
static void ReportWarning(std::string message, std::optional< lldb::user_id_t > debugger_id=std::nullopt, std::once_flag *once=nullptr)
Report warning events.
RegisterContext(Thread &thread, uint32_t concrete_frame_idx)
uint32_t SetFromMemoryData(const RegisterInfo &reg_info, const void *src, uint32_t src_len, lldb::ByteOrder src_byte_order, Status &error)
An error handling class.
Definition Status.h:118
#define UNUSED_IF_ASSERT_DISABLED(x)
#define LLDB_INVALID_REGNUM
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:338
constexpr RegsetDesc RISCV32_CSREGMAP_Desc[]
DataExtractor getRegset(llvm::ArrayRef< CoreNote > Notes, const llvm::Triple &Triple, llvm::ArrayRef< RegsetDesc > RegsetDescs)
constexpr RegsetDesc FPR_Desc[]
uint64_t offset_t
Definition lldb-types.h:86
ByteOrder
Byte ordering definitions.
@ eRegisterKindGeneric
insn ptr reg, stack ptr reg, etc not specific to any particular target
@ eRegisterKindLLDB
lldb's internal register numbers
@ eRegisterKindDWARF
the register numbers seen DWARF
@ eRegisterKindEHFrame
the register numbers seen in eh_frame
@ eRegisterKindProcessPlugin
num used by the process plugin - e.g.
Every register is described in detail including its name, alternate name (optional),...
lldb::Encoding encoding
Encoding of the register bits.
const char * alt_name
Alternate name of this register, can be NULL.
uint32_t * value_regs
List of registers (terminated with LLDB_INVALID_REGNUM).
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 RegisterType * register_type
If not nullptr, a type defined by XML descriptions.
const char * name
Name of this register, can't be NULL.
lldb::Format format
Default display format.
uint32_t * invalidate_regs
List of registers (terminated with LLDB_INVALID_REGNUM).
Registers are grouped into register sets.
const char * name
Name of this register set.