Skip to content

Commit 3f5fd4b

Browse files
[lldb][AArch64] Move register info reconfigure into architecture plugin (#70950)
This removes AArch64 specific code from the GDB* classes. To do this I've added 2 new methods to Architecture: * RegisterWriteCausesReconfigure to check if what you are about to do will trash the register info. * ReconfigureRegisterInfo to do the reconfiguring. This tells you if anything changed so that we only invalidate registers when needed. So that ProcessGDBRemote can call ReconfigureRegisterInfo in SetThreadStopInfo, I've added forwarding calls to GDBRemoteRegisterContext and the base class RegisterContext. (which removes a slightly sketchy static cast as well) RegisterContext defaults to doing nothing for both the methods so anything other than GDBRemoteRegisterContext will do nothing.
1 parent 7f5d59b commit 3f5fd4b

File tree

8 files changed

+169
-110
lines changed

8 files changed

+169
-110
lines changed

lldb/include/lldb/Core/Architecture.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define LLDB_CORE_ARCHITECTURE_H
1111

1212
#include "lldb/Core/PluginInterface.h"
13+
#include "lldb/Target/DynamicRegisterInfo.h"
1314
#include "lldb/Target/MemoryTagManager.h"
1415

1516
namespace lldb_private {
@@ -109,6 +110,25 @@ class Architecture : public PluginInterface {
109110
virtual const MemoryTagManager *GetMemoryTagManager() const {
110111
return nullptr;
111112
}
113+
114+
// This returns true if a write to the named register should cause lldb to
115+
// reconfigure its register information. For example on AArch64 writing to vg
116+
// to change the vector length means lldb has to change the size of registers.
117+
virtual bool
118+
RegisterWriteCausesReconfigure(const llvm::StringRef name) const {
119+
return false;
120+
}
121+
122+
// Call this after writing a register for which RegisterWriteCausesReconfigure
123+
// returns true. This method will update the layout of registers according to
124+
// the new state e.g. the new length of scalable vector registers.
125+
// Returns true if anything changed, which means existing register values must
126+
// be invalidated.
127+
virtual bool ReconfigureRegisterInfo(DynamicRegisterInfo &reg_info,
128+
DataExtractor &reg_data,
129+
RegisterContext &reg_context) const {
130+
return false;
131+
}
112132
};
113133

114134
} // namespace lldb_private

lldb/include/lldb/Target/DynamicRegisterInfo.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@ class DynamicRegisterInfo {
9393
return llvm::iterator_range<reg_collection::const_iterator>(m_regs);
9494
}
9595

96+
llvm::iterator_range<reg_collection::iterator> registers_mutable() {
97+
return llvm::iterator_range<reg_collection::iterator>(m_regs);
98+
}
99+
96100
void ConfigureOffsets();
97101

98102
protected:

lldb/include/lldb/Target/RegisterContext.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ class RegisterContext : public std::enable_shared_from_this<RegisterContext>,
5151
return false;
5252
}
5353

54+
virtual bool RegisterWriteCausesReconfigure(const llvm::StringRef name) {
55+
return false;
56+
}
57+
58+
virtual bool ReconfigureRegisterInfo() { return false; }
59+
5460
// These two functions are used to implement "push" and "pop" of register
5561
// states. They are used primarily for expression evaluation, where we need
5662
// to push a new state (storing the old one in data_sp) and then restoring

lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.cpp

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@
88

99
#include "Plugins/Architecture/AArch64/ArchitectureAArch64.h"
1010
#include "lldb/Core/PluginManager.h"
11+
#include "lldb/Target/RegisterContext.h"
1112
#include "lldb/Utility/ArchSpec.h"
13+
#include "lldb/Utility/DataBufferHeap.h"
14+
#include "lldb/Utility/DataExtractor.h"
1215

1316
using namespace lldb_private;
1417
using namespace lldb;
@@ -34,3 +37,91 @@ ArchitectureAArch64::Create(const ArchSpec &arch) {
3437
}
3538
return std::unique_ptr<Architecture>(new ArchitectureAArch64());
3639
}
40+
41+
static void UpdateARM64SVERegistersInfos(
42+
llvm::iterator_range<
43+
lldb_private::DynamicRegisterInfo::reg_collection::iterator>
44+
regs,
45+
uint64_t vg) {
46+
// SVE Z register size is vg x 8 bytes.
47+
uint32_t z_reg_byte_size = vg * 8;
48+
49+
// SVE vector length has changed, accordingly set size of Z, P and FFR
50+
// registers. Also invalidate register offsets it will be recalculated
51+
// after SVE register size update.
52+
for (auto &reg : regs) {
53+
if (reg.value_regs == nullptr) {
54+
if (reg.name[0] == 'z' && isdigit(reg.name[1]))
55+
reg.byte_size = z_reg_byte_size;
56+
else if (reg.name[0] == 'p' && isdigit(reg.name[1]))
57+
reg.byte_size = vg;
58+
else if (strcmp(reg.name, "ffr") == 0)
59+
reg.byte_size = vg;
60+
}
61+
reg.byte_offset = LLDB_INVALID_INDEX32;
62+
}
63+
}
64+
65+
static void UpdateARM64SMERegistersInfos(
66+
llvm::iterator_range<
67+
lldb_private::DynamicRegisterInfo::reg_collection::iterator>
68+
regs,
69+
uint64_t svg) {
70+
for (auto &reg : regs) {
71+
if (strcmp(reg.name, "za") == 0) {
72+
// ZA is a register with size (svg*8) * (svg*8). A square essentially.
73+
reg.byte_size = (svg * 8) * (svg * 8);
74+
}
75+
reg.byte_offset = LLDB_INVALID_INDEX32;
76+
}
77+
}
78+
79+
bool ArchitectureAArch64::ReconfigureRegisterInfo(DynamicRegisterInfo &reg_info,
80+
DataExtractor &reg_data,
81+
RegisterContext &reg_context
82+
83+
) const {
84+
// Once we start to reconfigure registers, we cannot read any of them.
85+
// So we must read VG and SVG up front.
86+
87+
const uint64_t fail_value = LLDB_INVALID_ADDRESS;
88+
std::optional<uint64_t> vg_reg_value;
89+
const RegisterInfo *vg_reg_info = reg_info.GetRegisterInfo("vg");
90+
if (vg_reg_info) {
91+
uint32_t vg_reg_num = vg_reg_info->kinds[eRegisterKindLLDB];
92+
uint64_t reg_value =
93+
reg_context.ReadRegisterAsUnsigned(vg_reg_num, fail_value);
94+
if (reg_value != fail_value && reg_value <= 32)
95+
vg_reg_value = reg_value;
96+
}
97+
98+
std::optional<uint64_t> svg_reg_value;
99+
const RegisterInfo *svg_reg_info = reg_info.GetRegisterInfo("svg");
100+
if (svg_reg_info) {
101+
uint32_t svg_reg_num = svg_reg_info->kinds[eRegisterKindLLDB];
102+
uint64_t reg_value =
103+
reg_context.ReadRegisterAsUnsigned(svg_reg_num, fail_value);
104+
if (reg_value != fail_value && reg_value <= 32)
105+
svg_reg_value = reg_value;
106+
}
107+
108+
if (!vg_reg_value && !svg_reg_value)
109+
return false;
110+
111+
if (vg_reg_value)
112+
UpdateARM64SVERegistersInfos(reg_info.registers_mutable(), *vg_reg_value);
113+
if (svg_reg_value)
114+
UpdateARM64SMERegistersInfos(reg_info.registers_mutable(), *svg_reg_value);
115+
116+
// At this point if we have updated any registers, their offsets will all be
117+
// invalid. If we did, we need to update them all.
118+
reg_info.ConfigureOffsets();
119+
// From here we are able to read registers again.
120+
121+
// Make a heap based buffer that is big enough to store all registers
122+
reg_data.SetData(
123+
std::make_shared<DataBufferHeap>(reg_info.GetRegisterDataByteSize(), 0));
124+
reg_data.SetByteOrder(reg_context.GetByteOrder());
125+
126+
return true;
127+
}

lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,17 @@ class ArchitectureAArch64 : public Architecture {
2828
return &m_memory_tag_manager;
2929
}
3030

31+
bool
32+
RegisterWriteCausesReconfigure(const llvm::StringRef name) const override {
33+
// lldb treats svg as read only, so only vg can be written. This results in
34+
// the SVE registers changing size.
35+
return name == "vg";
36+
}
37+
38+
bool ReconfigureRegisterInfo(DynamicRegisterInfo &reg_info,
39+
DataExtractor &reg_data,
40+
RegisterContext &reg_context) const override;
41+
3142
private:
3243
static std::unique_ptr<Architecture> Create(const ArchSpec &arch);
3344
ArchitectureAArch64() = default;

lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp

Lines changed: 26 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,19 @@
88

99
#include "GDBRemoteRegisterContext.h"
1010

11+
#include "ProcessGDBRemote.h"
12+
#include "ProcessGDBRemoteLog.h"
13+
#include "ThreadGDBRemote.h"
14+
#include "Utility/ARM_DWARF_Registers.h"
15+
#include "Utility/ARM_ehframe_Registers.h"
16+
#include "lldb/Core/Architecture.h"
1117
#include "lldb/Target/ExecutionContext.h"
1218
#include "lldb/Target/Target.h"
1319
#include "lldb/Utility/DataBufferHeap.h"
1420
#include "lldb/Utility/DataExtractor.h"
1521
#include "lldb/Utility/RegisterValue.h"
1622
#include "lldb/Utility/Scalar.h"
1723
#include "lldb/Utility/StreamString.h"
18-
#include "ProcessGDBRemote.h"
19-
#include "ProcessGDBRemoteLog.h"
20-
#include "ThreadGDBRemote.h"
21-
#include "Utility/ARM_DWARF_Registers.h"
22-
#include "Utility/ARM_ehframe_Registers.h"
2324
#include "lldb/Utility/StringExtractorGDBRemote.h"
2425

2526
#include <memory>
@@ -373,14 +374,8 @@ bool GDBRemoteRegisterContext::WriteRegisterBytes(const RegisterInfo *reg_info,
373374
if (dst == nullptr)
374375
return false;
375376

376-
// Code below is specific to AArch64 target in SVE or SME state
377-
// If vector granule (vg) register is being written then thread's
378-
// register context reconfiguration is triggered on success.
379-
// We do not allow writes to SVG so it is not mentioned here.
380-
const ArchSpec &arch = process->GetTarget().GetArchitecture();
381-
bool do_reconfigure_arm64_sve = arch.IsValid() &&
382-
arch.GetTriple().isAArch64() &&
383-
(strcmp(reg_info->name, "vg") == 0);
377+
const bool should_reconfigure_registers =
378+
RegisterWriteCausesReconfigure(reg_info->name);
384379

385380
if (data.CopyByteOrderedData(data_offset, // src offset
386381
reg_info->byte_size, // src length
@@ -400,8 +395,8 @@ bool GDBRemoteRegisterContext::WriteRegisterBytes(const RegisterInfo *reg_info,
400395
{m_reg_data.GetDataStart(), size_t(m_reg_data.GetByteSize())}))
401396

402397
{
403-
if (do_reconfigure_arm64_sve)
404-
AArch64Reconfigure();
398+
if (should_reconfigure_registers)
399+
ReconfigureRegisterInfo();
405400

406401
InvalidateAllRegisters();
407402

@@ -447,10 +442,9 @@ bool GDBRemoteRegisterContext::WriteRegisterBytes(const RegisterInfo *reg_info,
447442
false);
448443
}
449444

450-
if (success && do_reconfigure_arm64_sve) {
451-
AArch64Reconfigure();
445+
if (success && should_reconfigure_registers &&
446+
ReconfigureRegisterInfo())
452447
InvalidateAllRegisters();
453-
}
454448

455449
return success;
456450
}
@@ -762,75 +756,20 @@ uint32_t GDBRemoteRegisterContext::ConvertRegisterKindToRegisterNumber(
762756
return m_reg_info_sp->ConvertRegisterKindToRegisterNumber(kind, num);
763757
}
764758

765-
void GDBRemoteRegisterContext::AArch64Reconfigure() {
766-
assert(m_reg_info_sp);
767-
768-
// Once we start to reconfigure registers, we cannot read any of them.
769-
// So we must read VG and SVG up front.
770-
771-
const uint64_t fail_value = LLDB_INVALID_ADDRESS;
772-
std::optional<uint64_t> vg_reg_value;
773-
const RegisterInfo *vg_reg_info = m_reg_info_sp->GetRegisterInfo("vg");
774-
if (vg_reg_info) {
775-
uint32_t vg_reg_num = vg_reg_info->kinds[eRegisterKindLLDB];
776-
uint64_t reg_value = ReadRegisterAsUnsigned(vg_reg_num, fail_value);
777-
if (reg_value != fail_value && reg_value <= 32)
778-
vg_reg_value = reg_value;
779-
}
780-
781-
std::optional<uint64_t> svg_reg_value;
782-
const RegisterInfo *svg_reg_info = m_reg_info_sp->GetRegisterInfo("svg");
783-
if (svg_reg_info) {
784-
uint32_t svg_reg_num = svg_reg_info->kinds[eRegisterKindLLDB];
785-
uint64_t reg_value = ReadRegisterAsUnsigned(svg_reg_num, fail_value);
786-
if (reg_value != fail_value && reg_value <= 32)
787-
svg_reg_value = reg_value;
788-
}
789-
790-
if (vg_reg_value)
791-
m_reg_info_sp->UpdateARM64SVERegistersInfos(*vg_reg_value);
792-
if (svg_reg_value)
793-
m_reg_info_sp->UpdateARM64SMERegistersInfos(*svg_reg_value);
794-
795-
// At this point if we have updated any registers, their offsets will all be
796-
// invalid. If we did, we need to update them all.
797-
if (vg_reg_value || svg_reg_value) {
798-
m_reg_info_sp->ConfigureOffsets();
799-
// From here we are able to read registers again.
800-
801-
// Make a heap based buffer that is big enough to store all registers
802-
m_reg_data.SetData(std::make_shared<DataBufferHeap>(
803-
m_reg_info_sp->GetRegisterDataByteSize(), 0));
804-
m_reg_data.SetByteOrder(GetByteOrder());
805-
}
806-
}
807-
808-
void GDBRemoteDynamicRegisterInfo::UpdateARM64SVERegistersInfos(uint64_t vg) {
809-
// SVE Z register size is vg x 8 bytes.
810-
uint32_t z_reg_byte_size = vg * 8;
811-
812-
// SVE vector length has changed, accordingly set size of Z, P and FFR
813-
// registers. Also invalidate register offsets it will be recalculated
814-
// after SVE register size update.
815-
for (auto &reg : m_regs) {
816-
if (reg.value_regs == nullptr) {
817-
if (reg.name[0] == 'z' && isdigit(reg.name[1]))
818-
reg.byte_size = z_reg_byte_size;
819-
else if (reg.name[0] == 'p' && isdigit(reg.name[1]))
820-
reg.byte_size = vg;
821-
else if (strcmp(reg.name, "ffr") == 0)
822-
reg.byte_size = vg;
823-
}
824-
reg.byte_offset = LLDB_INVALID_INDEX32;
825-
}
759+
bool GDBRemoteRegisterContext::RegisterWriteCausesReconfigure(
760+
const llvm::StringRef name) {
761+
ExecutionContext exe_ctx(CalculateThread());
762+
const Architecture *architecture =
763+
exe_ctx.GetProcessRef().GetTarget().GetArchitecturePlugin();
764+
return architecture && architecture->RegisterWriteCausesReconfigure(name);
826765
}
827766

828-
void GDBRemoteDynamicRegisterInfo::UpdateARM64SMERegistersInfos(uint64_t svg) {
829-
for (auto &reg : m_regs) {
830-
if (strcmp(reg.name, "za") == 0) {
831-
// ZA is a register with size (svg*8) * (svg*8). A square essentially.
832-
reg.byte_size = (svg * 8) * (svg * 8);
833-
}
834-
reg.byte_offset = LLDB_INVALID_INDEX32;
835-
}
767+
bool GDBRemoteRegisterContext::ReconfigureRegisterInfo() {
768+
ExecutionContext exe_ctx(CalculateThread());
769+
const Architecture *architecture =
770+
exe_ctx.GetProcessRef().GetTarget().GetArchitecturePlugin();
771+
if (architecture)
772+
return architecture->ReconfigureRegisterInfo(*(m_reg_info_sp.get()),
773+
m_reg_data, *this);
774+
return false;
836775
}

lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,9 @@ class GDBRemoteRegisterContext : public RegisterContext {
7878
uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
7979
uint32_t num) override;
8080

81-
// Reconfigure variable sized registers for AArch64 SVE and SME.
82-
void AArch64Reconfigure();
81+
bool RegisterWriteCausesReconfigure(const llvm::StringRef name) override;
82+
83+
bool ReconfigureRegisterInfo() override;
8384

8485
protected:
8586
friend class ThreadGDBRemote;

lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1667,27 +1667,14 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(
16671667

16681668
ParseExpeditedRegisters(expedited_register_map, thread_sp);
16691669

1670-
// AArch64 SVE/SME specific code below updates SVE and ZA register sizes and
1671-
// offsets if value of VG or SVG registers has changed since last stop.
1672-
const ArchSpec &arch = GetTarget().GetArchitecture();
1673-
if (arch.IsValid() && arch.GetTriple().isAArch64()) {
1674-
GDBRemoteRegisterContext *reg_ctx_sp =
1675-
static_cast<GDBRemoteRegisterContext *>(
1676-
gdb_thread->GetRegisterContext().get());
1677-
1678-
if (reg_ctx_sp) {
1679-
reg_ctx_sp->AArch64Reconfigure();
1680-
// Now we have changed the offsets of all the registers, so the values
1681-
// will be corrupted.
1682-
reg_ctx_sp->InvalidateAllRegisters();
1683-
1684-
// Expedited registers values will never contain registers that would be
1685-
// resized by AArch64Reconfigure. So we are safe to continue using these
1686-
// values. These values include vg, svg and useful general purpose
1687-
// registers so this saves a few read packets each time we make use of
1688-
// them.
1689-
ParseExpeditedRegisters(expedited_register_map, thread_sp);
1690-
}
1670+
if (reg_ctx_sp->ReconfigureRegisterInfo()) {
1671+
// Now we have changed the offsets of all the registers, so the values
1672+
// will be corrupted.
1673+
reg_ctx_sp->InvalidateAllRegisters();
1674+
// Expedited registers values will never contain registers that would be
1675+
// resized by a reconfigure. So we are safe to continue using these
1676+
// values.
1677+
ParseExpeditedRegisters(expedited_register_map, thread_sp);
16911678
}
16921679

16931680
thread_sp->SetName(thread_name.empty() ? nullptr : thread_name.c_str());

0 commit comments

Comments
 (0)