Skip to content

Commit 660e34f

Browse files
[lldb][RISCV] Support optionally disabled FPR for riscv64 (#104547)
The PR adds the support optionally enabled/disabled FP-registers to LLDB `RegisterInfoPOSIX_riscv64`. This situation might take place for RISC-V builds having no FP-registers, like RV64IMAC or RV64IMACV. To aim this, patch adds `opt_regsets` flags mechanism. It re-works RegisterInfo class to work with flexibly allocated (depending on `opt_regsets` flag) `m_register_sets` and `m_register_infos` vectors instead of statically defined structures. The registration of regsets is being arranged by `m_per_regset_regnum_range` map. The patch flows are spread to `NativeRegisterContextLinux_riscv64` and `RegisterContextCorePOSIX_riscv64` classes, that were tested on: - x86_64 host working with coredumps - RV64GC and RV64IMAC targets working with coredumps and natively in run-time with binaries `EmulateInstructionRISCV` is out of scope of this patch, and its behavior did not change, using maximum set of registers. According testcase built for RV64IMAC (no-FPR) was added to `TestLinuxCore.py`.
1 parent f7fa75b commit 660e34f

16 files changed

+300
-169
lines changed

lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1748,10 +1748,10 @@ EmulateInstructionRISCV::GetRegisterInfo(RegisterKind reg_kind,
17481748
}
17491749
}
17501750

1751-
const RegisterInfo *array =
1752-
RegisterInfoPOSIX_riscv64::GetRegisterInfoPtr(m_arch);
1753-
const uint32_t length =
1754-
RegisterInfoPOSIX_riscv64::GetRegisterInfoCount(m_arch);
1751+
RegisterInfoPOSIX_riscv64 reg_info(m_arch,
1752+
RegisterInfoPOSIX_riscv64::eRegsetMaskAll);
1753+
const RegisterInfo *array = reg_info.GetRegisterInfo();
1754+
const uint32_t length = reg_info.GetRegisterCount();
17551755

17561756
if (reg_index >= length || reg_kind != eRegisterKindLLDB)
17571757
return {};

lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_riscv64.cpp

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,11 @@
2323

2424
// System includes - They have to be included after framework includes because
2525
// they define some macros which collide with variable names in other modules
26+
#include <sys/ptrace.h>
2627
#include <sys/uio.h>
2728
// NT_PRSTATUS and NT_FPREGSET definition
2829
#include <elf.h>
2930

30-
#define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize())
31-
3231
using namespace lldb;
3332
using namespace lldb_private;
3433
using namespace lldb_private::process_linux;
@@ -38,7 +37,21 @@ NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
3837
const ArchSpec &target_arch, NativeThreadLinux &native_thread) {
3938
switch (target_arch.GetMachine()) {
4039
case llvm::Triple::riscv64: {
41-
Flags opt_regsets;
40+
Flags opt_regsets(RegisterInfoPOSIX_riscv64::eRegsetMaskDefault);
41+
42+
RegisterInfoPOSIX_riscv64::FPR fpr;
43+
struct iovec ioVec;
44+
ioVec.iov_base = &fpr;
45+
ioVec.iov_len = sizeof(fpr);
46+
unsigned int regset = NT_FPREGSET;
47+
48+
if (NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET,
49+
native_thread.GetID(), &regset,
50+
&ioVec, sizeof(fpr))
51+
.Success()) {
52+
opt_regsets.Set(RegisterInfoPOSIX_riscv64::eRegsetMaskFP);
53+
}
54+
4255
auto register_info_up =
4356
std::make_unique<RegisterInfoPOSIX_riscv64>(target_arch, opt_regsets);
4457
return std::make_unique<NativeRegisterContextLinux_riscv64>(
@@ -194,20 +207,23 @@ Status NativeRegisterContextLinux_riscv64::ReadAllRegisterValues(
194207
lldb::WritableDataBufferSP &data_sp) {
195208
Status error;
196209

197-
data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
210+
data_sp.reset(new DataBufferHeap(GetRegContextSize(), 0));
198211

199212
error = ReadGPR();
200213
if (error.Fail())
201214
return error;
202215

203-
error = ReadFPR();
204-
if (error.Fail())
205-
return error;
216+
if (GetRegisterInfo().IsFPPresent()) {
217+
error = ReadFPR();
218+
if (error.Fail())
219+
return error;
220+
}
206221

207222
uint8_t *dst = const_cast<uint8_t *>(data_sp->GetBytes());
208223
::memcpy(dst, GetGPRBuffer(), GetGPRSize());
209224
dst += GetGPRSize();
210-
::memcpy(dst, GetFPRBuffer(), GetFPRSize());
225+
if (GetRegisterInfo().IsFPPresent())
226+
::memcpy(dst, GetFPRBuffer(), GetFPRSize());
211227

212228
return error;
213229
}
@@ -223,11 +239,11 @@ Status NativeRegisterContextLinux_riscv64::WriteAllRegisterValues(
223239
return error;
224240
}
225241

226-
if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
242+
if (data_sp->GetByteSize() != GetRegContextSize()) {
227243
error = Status::FromErrorStringWithFormat(
228244
"NativeRegisterContextLinux_riscv64::%s data_sp contained mismatched "
229245
"data size, expected %" PRIu64 ", actual %" PRIu64,
230-
__FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
246+
__FUNCTION__, GetRegContextSize(), data_sp->GetByteSize());
231247
return error;
232248
}
233249

@@ -247,23 +263,32 @@ Status NativeRegisterContextLinux_riscv64::WriteAllRegisterValues(
247263
return error;
248264

249265
src += GetRegisterInfoInterface().GetGPRSize();
250-
::memcpy(GetFPRBuffer(), src, GetFPRSize());
251266

252-
error = WriteFPR();
253-
if (error.Fail())
254-
return error;
267+
if (GetRegisterInfo().IsFPPresent()) {
268+
::memcpy(GetFPRBuffer(), src, GetFPRSize());
269+
270+
error = WriteFPR();
271+
if (error.Fail())
272+
return error;
273+
}
255274

256275
return error;
257276
}
258277

278+
size_t NativeRegisterContextLinux_riscv64::GetRegContextSize() {
279+
size_t size = GetGPRSize();
280+
if (GetRegisterInfo().IsFPPresent())
281+
size += GetFPRSize();
282+
return size;
283+
}
284+
259285
bool NativeRegisterContextLinux_riscv64::IsGPR(unsigned reg) const {
260286
return GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
261287
RegisterInfoPOSIX_riscv64::GPRegSet;
262288
}
263289

264290
bool NativeRegisterContextLinux_riscv64::IsFPR(unsigned reg) const {
265-
return GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
266-
RegisterInfoPOSIX_riscv64::FPRegSet;
291+
return GetRegisterInfo().IsFPReg(reg);
267292
}
268293

269294
Status NativeRegisterContextLinux_riscv64::ReadGPR() {

lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_riscv64.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ class NativeRegisterContextLinux_riscv64 : public NativeRegisterContextLinux {
7575

7676
RegisterInfoPOSIX_riscv64::FPR m_fpr;
7777

78+
size_t GetRegContextSize();
79+
7880
bool IsGPR(unsigned reg) const;
7981

8082
bool IsFPR(unsigned reg) const;

lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_riscv64.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,5 @@ bool RegisterContextPOSIX_riscv64::IsGPR(unsigned int reg) {
7777
}
7878

7979
bool RegisterContextPOSIX_riscv64::IsFPR(unsigned int reg) {
80-
return m_register_info_up->GetRegisterSetFromRegisterIndex(reg) ==
81-
RegisterInfoPOSIX_riscv64::FPRegSet;
80+
return m_register_info_up->IsFPReg(reg);
8281
}

lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.cpp

Lines changed: 70 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -18,42 +18,15 @@
1818
#define GPR_OFFSET(idx) ((idx)*8 + 0)
1919
#define FPR_OFFSET(idx) ((idx)*8 + sizeof(RegisterInfoPOSIX_riscv64::GPR))
2020

21-
#define REG_CONTEXT_SIZE \
22-
(sizeof(RegisterInfoPOSIX_riscv64::GPR) + \
23-
sizeof(RegisterInfoPOSIX_riscv64::FPR))
24-
2521
#define DECLARE_REGISTER_INFOS_RISCV64_STRUCT
2622
#include "RegisterInfos_riscv64.h"
2723
#undef DECLARE_REGISTER_INFOS_RISCV64_STRUCT
2824

29-
const lldb_private::RegisterInfo *RegisterInfoPOSIX_riscv64::GetRegisterInfoPtr(
30-
const lldb_private::ArchSpec &target_arch) {
31-
switch (target_arch.GetMachine()) {
32-
case llvm::Triple::riscv64:
33-
return g_register_infos_riscv64_le;
34-
default:
35-
assert(false && "Unhandled target architecture.");
36-
return nullptr;
37-
}
38-
}
39-
40-
uint32_t RegisterInfoPOSIX_riscv64::GetRegisterInfoCount(
41-
const lldb_private::ArchSpec &target_arch) {
42-
switch (target_arch.GetMachine()) {
43-
case llvm::Triple::riscv64:
44-
return static_cast<uint32_t>(sizeof(g_register_infos_riscv64_le) /
45-
sizeof(g_register_infos_riscv64_le[0]));
46-
default:
47-
assert(false && "Unhandled target architecture.");
48-
return 0;
49-
}
50-
}
51-
5225
// Number of register sets provided by this context.
5326
enum {
5427
k_num_gpr_registers = gpr_last_riscv - gpr_first_riscv + 1,
5528
k_num_fpr_registers = fpr_last_riscv - fpr_first_riscv + 1,
56-
k_num_register_sets = 2
29+
k_num_register_sets_default = 1
5730
};
5831

5932
// RISC-V64 general purpose registers.
@@ -73,38 +46,69 @@ static_assert(((sizeof g_gpr_regnums_riscv64 /
7346
1) == k_num_gpr_registers,
7447
"g_gpr_regnums_riscv64 has wrong number of register infos");
7548

76-
// RISC-V64 floating point registers.
77-
static const uint32_t g_fpr_regnums_riscv64[] = {
78-
fpr_f0_riscv, fpr_f1_riscv, fpr_f2_riscv, fpr_f3_riscv,
79-
fpr_f4_riscv, fpr_f5_riscv, fpr_f6_riscv, fpr_f7_riscv,
80-
fpr_f8_riscv, fpr_f9_riscv, fpr_f10_riscv, fpr_f11_riscv,
81-
fpr_f12_riscv, fpr_f13_riscv, fpr_f14_riscv, fpr_f15_riscv,
82-
fpr_f16_riscv, fpr_f17_riscv, fpr_f18_riscv, fpr_f19_riscv,
83-
fpr_f20_riscv, fpr_f21_riscv, fpr_f22_riscv, fpr_f23_riscv,
84-
fpr_f24_riscv, fpr_f25_riscv, fpr_f26_riscv, fpr_f27_riscv,
85-
fpr_f28_riscv, fpr_f29_riscv, fpr_f30_riscv, fpr_f31_riscv,
86-
fpr_fcsr_riscv, LLDB_INVALID_REGNUM};
87-
88-
static_assert(((sizeof g_fpr_regnums_riscv64 /
89-
sizeof g_fpr_regnums_riscv64[0]) -
90-
1) == k_num_fpr_registers,
91-
"g_fpr_regnums_riscv64 has wrong number of register infos");
92-
9349
// Register sets for RISC-V64.
94-
static const lldb_private::RegisterSet g_reg_sets_riscv64[k_num_register_sets] =
95-
{{"General Purpose Registers", "gpr", k_num_gpr_registers,
96-
g_gpr_regnums_riscv64},
97-
{"Floating Point Registers", "fpr", k_num_fpr_registers,
98-
g_fpr_regnums_riscv64}};
50+
static const lldb_private::RegisterSet g_reg_set_gpr_riscv64 = {
51+
"General Purpose Registers", "gpr", k_num_gpr_registers,
52+
g_gpr_regnums_riscv64};
53+
static const lldb_private::RegisterSet g_reg_set_fpr_riscv64 = {
54+
"Floating Point Registers", "fpr", k_num_fpr_registers, nullptr};
9955

10056
RegisterInfoPOSIX_riscv64::RegisterInfoPOSIX_riscv64(
101-
const lldb_private::ArchSpec &target_arch, lldb_private::Flags flags)
57+
const lldb_private::ArchSpec &target_arch, lldb_private::Flags opt_regsets)
10258
: lldb_private::RegisterInfoAndSetInterface(target_arch),
103-
m_register_info_p(GetRegisterInfoPtr(target_arch)),
104-
m_register_info_count(GetRegisterInfoCount(target_arch)) {}
59+
m_opt_regsets(opt_regsets) {
60+
switch (target_arch.GetMachine()) {
61+
case llvm::Triple::riscv64: {
62+
// By-default considering RISC-V has only GPR.
63+
// Other register sets could be enabled optionally by opt_regsets.
64+
AddRegSetGP();
65+
66+
if (m_opt_regsets.AnySet(eRegsetMaskFP))
67+
AddRegSetFP();
68+
69+
break;
70+
}
71+
default:
72+
assert(false && "Unhandled target architecture.");
73+
}
74+
}
75+
76+
void RegisterInfoPOSIX_riscv64::AddRegSetGP() {
77+
m_register_infos.resize(k_num_gpr_registers);
78+
memcpy(&m_register_infos[0], g_register_infos_riscv64_gpr,
79+
sizeof(g_register_infos_riscv64_gpr));
80+
m_register_sets.push_back(g_reg_set_gpr_riscv64);
81+
82+
m_per_regset_regnum_range[GPRegSet] =
83+
std::make_pair(gpr_first_riscv, m_register_infos.size());
84+
}
85+
86+
void RegisterInfoPOSIX_riscv64::AddRegSetFP() {
87+
const uint32_t register_info_count = m_register_infos.size();
88+
const uint32_t register_set_count = m_register_sets.size();
89+
90+
// Filling m_register_infos.
91+
// For FPR case we do not need to correct register offsets and kinds
92+
// while for other further cases (like VPR), register offset/kind
93+
// should be started counting from the last one in previously added
94+
// regset. This is needed for the case e.g. when architecture has GPR + VPR
95+
// sets only.
96+
m_register_infos.resize(register_info_count + k_num_fpr_registers);
97+
memcpy(&m_register_infos[register_info_count], g_register_infos_riscv64_fpr,
98+
sizeof(g_register_infos_riscv64_fpr));
99+
100+
// Filling m_register_sets with enabled register set
101+
for (uint32_t i = 0; i < k_num_fpr_registers; i++)
102+
m_fp_regnum_collection.push_back(register_info_count + i);
103+
m_register_sets.push_back(g_reg_set_fpr_riscv64);
104+
m_register_sets.back().registers = m_fp_regnum_collection.data();
105+
106+
m_per_regset_regnum_range[register_set_count] =
107+
std::make_pair(register_info_count, m_register_infos.size());
108+
}
105109

106110
uint32_t RegisterInfoPOSIX_riscv64::GetRegisterCount() const {
107-
return m_register_info_count;
111+
return m_register_infos.size();
108112
}
109113

110114
size_t RegisterInfoPOSIX_riscv64::GetGPRSize() const {
@@ -117,26 +121,30 @@ size_t RegisterInfoPOSIX_riscv64::GetFPRSize() const {
117121

118122
const lldb_private::RegisterInfo *
119123
RegisterInfoPOSIX_riscv64::GetRegisterInfo() const {
120-
return m_register_info_p;
124+
return m_register_infos.data();
121125
}
122126

123127
size_t RegisterInfoPOSIX_riscv64::GetRegisterSetCount() const {
124-
return k_num_register_sets;
128+
return m_register_sets.size();
125129
}
126130

127131
size_t RegisterInfoPOSIX_riscv64::GetRegisterSetFromRegisterIndex(
128132
uint32_t reg_index) const {
129-
// coverity[unsigned_compare]
130-
if (reg_index >= gpr_first_riscv && reg_index <= gpr_last_riscv)
131-
return GPRegSet;
132-
if (reg_index >= fpr_first_riscv && reg_index <= fpr_last_riscv)
133-
return FPRegSet;
133+
for (const auto &regset_range : m_per_regset_regnum_range) {
134+
if (reg_index >= regset_range.second.first &&
135+
reg_index < regset_range.second.second)
136+
return regset_range.first;
137+
}
134138
return LLDB_INVALID_REGNUM;
135139
}
136140

141+
bool RegisterInfoPOSIX_riscv64::IsFPReg(unsigned reg) const {
142+
return llvm::is_contained(m_fp_regnum_collection, reg);
143+
}
144+
137145
const lldb_private::RegisterSet *
138146
RegisterInfoPOSIX_riscv64::GetRegisterSet(size_t set_index) const {
139147
if (set_index < GetRegisterSetCount())
140-
return &g_reg_sets_riscv64[set_index];
148+
return &m_register_sets[set_index];
141149
return nullptr;
142150
}

lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.h

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,21 @@
1111

1212
#include "RegisterInfoAndSetInterface.h"
1313
#include "lldb/Target/RegisterContext.h"
14+
#include "lldb/Utility/Flags.h"
1415
#include "lldb/lldb-private.h"
1516
#include <map>
1617

1718
class RegisterInfoPOSIX_riscv64
1819
: public lldb_private::RegisterInfoAndSetInterface {
1920
public:
20-
static const lldb_private::RegisterInfo *
21-
GetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch);
22-
static uint32_t
23-
GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch);
21+
enum { GPRegSet = 0 };
2422

25-
public:
26-
enum { GPRegSet = 0, FPRegSet };
23+
// RISC-V64 register set mask value
24+
enum {
25+
eRegsetMaskDefault = 0,
26+
eRegsetMaskFP = 1,
27+
eRegsetMaskAll = -1,
28+
};
2729

2830
struct GPR {
2931
// note: gpr[0] is pc, not x0
@@ -41,7 +43,11 @@ class RegisterInfoPOSIX_riscv64
4143
};
4244

4345
RegisterInfoPOSIX_riscv64(const lldb_private::ArchSpec &target_arch,
44-
lldb_private::Flags flags);
46+
lldb_private::Flags opt_regsets);
47+
48+
void AddRegSetGP();
49+
50+
void AddRegSetFP();
4551

4652
size_t GetGPRSize() const override;
4753

@@ -58,9 +64,23 @@ class RegisterInfoPOSIX_riscv64
5864

5965
size_t GetRegisterSetFromRegisterIndex(uint32_t reg_index) const override;
6066

67+
bool IsFPPresent() const { return m_opt_regsets.AnySet(eRegsetMaskFP); }
68+
69+
bool IsFPReg(unsigned reg) const;
70+
6171
private:
62-
const lldb_private::RegisterInfo *m_register_info_p;
63-
uint32_t m_register_info_count;
72+
std::vector<lldb_private::RegisterInfo> m_register_infos;
73+
74+
std::vector<lldb_private::RegisterSet> m_register_sets;
75+
76+
// Contains pair of [start, end] register numbers of a register set with start
77+
// and end included.
78+
std::map<uint32_t, std::pair<uint32_t, uint32_t>> m_per_regset_regnum_range;
79+
80+
// Register collections to be stored as reference for m_register_sets items
81+
std::vector<uint32_t> m_fp_regnum_collection;
82+
83+
lldb_private::Flags m_opt_regsets;
6484
};
6585

6686
#endif

0 commit comments

Comments
 (0)