Skip to content

Commit 805a36a

Browse files
[lldb][AArch64] Simplify handing of scalable registers using vg and svg (#70914)
This removes explicit invalidation of vg and svg that was done in `GDBRemoteRegisterContext::AArch64Reconfigure`. This was in fact covering up a bug elsehwere. Register information says that a write to vg also invalidates svg (it does not unless you are in streaming mode, but we decided to keep it simple and say it always does). This invalidation was not being applied until *after* AArch64Reconfigure was called. This meant that without those manual invalidates this happened: * vg is written * svg is not invalidated * Reconfigure uses the written vg value * Reconfigure uses the *old* svg value I have moved the AArch64Reconfigure call to after we've processed the invalidations caused by the register write, so we no longer need the manual invalidates in AArch64Reconfigure. In addition I have changed the order in which expedited registers as parsed. These registers come with a stop notification and include, amongst others, vg and svg. So now we: * Parse them and update register values (including vg and svg) * AArch64Reconfigure, which uses those values, and invalidates every register, because offsets may have changed. * Parse the expedited registers again, knowing that none of the values will have changed due to the scaling. This means we use the expedited registers during the reconfigure, but the invalidate does not mean we throw all of them away. The cost is we parse them twice client side, but this is cheap compared to a network packet, and is limited to AArch64 targets only. On a system with SVE and SME, these are the packets sent for a step: ``` (lldb) b-remote.async> < 803> read packet: $T05thread:p1f80.1f80;name:main.o;threads:1f80;thread-pcs:000000000040056c<...>a1:0800000000000000;d9:0400000000000000;reason:trace;#fc intern-state < 21> send packet: $xfffffffff200,200#5e intern-state < 516> read packet: $e4f2ffffffff000000<...>#71 intern-state < 15> send packet: $Z0,400568,4#4d intern-state < 6> read packet: $OK#9a dbg.evt-handler < 16> send packet: $jThreadsInfo#c1 dbg.evt-handler < 224> read packet: $[{"name":"main.o","reason":"trace","registers":{"161":"0800000000000000",<...>}],"signal":5,"tid":8064}]]#73 ``` You can see there are no extra register reads which means we're using the expedited registers. For a write to vg: ``` (lldb) register write vg 4 lldb < 37> send packet: $Pa1=0400000000000000;thread:1f80;#4a lldb < 6> read packet: $OK#9a lldb < 20> send packet: $pa1;thread:1f80;#29 lldb < 20> read packet: $0400000000000000#04 lldb < 20> send packet: $pd9;thread:1f80;#34 lldb < 20> read packet: $0400000000000000#04 ``` There is the initial P write, and lldb correctly assumes that SVG is invalidated by this also so we read back the new vg and svg values afterwards.
1 parent 22f1159 commit 805a36a

File tree

3 files changed

+45
-30
lines changed

3 files changed

+45
-30
lines changed

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

+5-12
Original file line numberDiff line numberDiff line change
@@ -434,11 +434,6 @@ bool GDBRemoteRegisterContext::WriteRegisterBytes(const RegisterInfo *reg_info,
434434
} else {
435435
// This is an actual register, write it
436436
success = SetPrimordialRegister(reg_info, gdb_comm);
437-
438-
if (success && do_reconfigure_arm64_sve) {
439-
AArch64Reconfigure();
440-
InvalidateAllRegisters();
441-
}
442437
}
443438

444439
// Check if writing this register will invalidate any other register
@@ -452,6 +447,11 @@ bool GDBRemoteRegisterContext::WriteRegisterBytes(const RegisterInfo *reg_info,
452447
false);
453448
}
454449

450+
if (success && do_reconfigure_arm64_sve) {
451+
AArch64Reconfigure();
452+
InvalidateAllRegisters();
453+
}
454+
455455
return success;
456456
}
457457
} else {
@@ -772,8 +772,6 @@ void GDBRemoteRegisterContext::AArch64Reconfigure() {
772772
std::optional<uint64_t> vg_reg_value;
773773
const RegisterInfo *vg_reg_info = m_reg_info_sp->GetRegisterInfo("vg");
774774
if (vg_reg_info) {
775-
// Make sure we get the latest value of vg from the remote.
776-
SetRegisterIsValid(vg_reg_info, false);
777775
uint32_t vg_reg_num = vg_reg_info->kinds[eRegisterKindLLDB];
778776
uint64_t reg_value = ReadRegisterAsUnsigned(vg_reg_num, fail_value);
779777
if (reg_value != fail_value && reg_value <= 32)
@@ -783,11 +781,6 @@ void GDBRemoteRegisterContext::AArch64Reconfigure() {
783781
std::optional<uint64_t> svg_reg_value;
784782
const RegisterInfo *svg_reg_info = m_reg_info_sp->GetRegisterInfo("svg");
785783
if (svg_reg_info) {
786-
// When vg is written it is automatically made invalid. Writing vg will also
787-
// change svg if we're in streaming mode but it will not be made invalid
788-
// so do this manually so the following read gets the latest svg value.
789-
SetRegisterIsValid(svg_reg_info, false);
790-
791784
uint32_t svg_reg_num = svg_reg_info->kinds[eRegisterKindLLDB];
792785
uint64_t reg_value = ReadRegisterAsUnsigned(svg_reg_num, fail_value);
793786
if (reg_value != fail_value && reg_value <= 32)

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

+37-18
Original file line numberDiff line numberDiff line change
@@ -1612,6 +1612,22 @@ bool ProcessGDBRemote::CalculateThreadStopInfo(ThreadGDBRemote *thread) {
16121612
return false;
16131613
}
16141614

1615+
void ProcessGDBRemote::ParseExpeditedRegisters(
1616+
ExpeditedRegisterMap &expedited_register_map, ThreadSP thread_sp) {
1617+
ThreadGDBRemote *gdb_thread = static_cast<ThreadGDBRemote *>(thread_sp.get());
1618+
RegisterContextSP gdb_reg_ctx_sp(gdb_thread->GetRegisterContext());
1619+
1620+
for (const auto &pair : expedited_register_map) {
1621+
StringExtractor reg_value_extractor(pair.second);
1622+
WritableDataBufferSP buffer_sp(
1623+
new DataBufferHeap(reg_value_extractor.GetStringRef().size() / 2, 0));
1624+
reg_value_extractor.GetHexBytes(buffer_sp->GetData(), '\xcc');
1625+
uint32_t lldb_regnum = gdb_reg_ctx_sp->ConvertRegisterKindToRegisterNumber(
1626+
eRegisterKindProcessPlugin, pair.first);
1627+
gdb_thread->PrivateSetRegisterValue(lldb_regnum, buffer_sp->GetData());
1628+
}
1629+
}
1630+
16151631
ThreadSP ProcessGDBRemote::SetThreadStopInfo(
16161632
lldb::tid_t tid, ExpeditedRegisterMap &expedited_register_map,
16171633
uint8_t signo, const std::string &thread_name, const std::string &reason,
@@ -1646,32 +1662,35 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(
16461662

16471663
reg_ctx_sp->InvalidateIfNeeded(true);
16481664

1665+
auto iter = std::find(m_thread_ids.begin(), m_thread_ids.end(), tid);
1666+
if (iter != m_thread_ids.end())
1667+
SetThreadPc(thread_sp, iter - m_thread_ids.begin());
1668+
1669+
ParseExpeditedRegisters(expedited_register_map, thread_sp);
1670+
16491671
// AArch64 SVE/SME specific code below updates SVE and ZA register sizes and
16501672
// offsets if value of VG or SVG registers has changed since last stop.
16511673
const ArchSpec &arch = GetTarget().GetArchitecture();
16521674
if (arch.IsValid() && arch.GetTriple().isAArch64()) {
1653-
GDBRemoteRegisterContext *gdb_remote_reg_ctx =
1654-
static_cast<GDBRemoteRegisterContext *>(reg_ctx_sp.get());
1675+
GDBRemoteRegisterContext *reg_ctx_sp =
1676+
static_cast<GDBRemoteRegisterContext *>(
1677+
gdb_thread->GetRegisterContext().get());
16551678

1656-
if (gdb_remote_reg_ctx) {
1657-
gdb_remote_reg_ctx->AArch64Reconfigure();
1658-
gdb_remote_reg_ctx->InvalidateAllRegisters();
1679+
if (reg_ctx_sp) {
1680+
reg_ctx_sp->AArch64Reconfigure();
1681+
// Now we have changed the offsets of all the registers, so the values
1682+
// will be corrupted.
1683+
reg_ctx_sp->InvalidateAllRegisters();
1684+
1685+
// Expedited registers values will never contain registers that would be
1686+
// resized by AArch64Reconfigure. So we are safe to continue using these
1687+
// values. These values include vg, svg and useful general purpose
1688+
// registers so this saves a few read packets each time we make use of
1689+
// them.
1690+
ParseExpeditedRegisters(expedited_register_map, thread_sp);
16591691
}
16601692
}
16611693

1662-
auto iter = std::find(m_thread_ids.begin(), m_thread_ids.end(), tid);
1663-
if (iter != m_thread_ids.end())
1664-
SetThreadPc(thread_sp, iter - m_thread_ids.begin());
1665-
1666-
for (const auto &pair : expedited_register_map) {
1667-
StringExtractor reg_value_extractor(pair.second);
1668-
WritableDataBufferSP buffer_sp(
1669-
new DataBufferHeap(reg_value_extractor.GetStringRef().size() / 2, 0));
1670-
reg_value_extractor.GetHexBytes(buffer_sp->GetData(), '\xcc');
1671-
uint32_t lldb_regnum = reg_ctx_sp->ConvertRegisterKindToRegisterNumber(
1672-
eRegisterKindProcessPlugin, pair.first);
1673-
gdb_thread->PrivateSetRegisterValue(lldb_regnum, buffer_sp->GetData());
1674-
}
16751694
thread_sp->SetName(thread_name.empty() ? nullptr : thread_name.c_str());
16761695

16771696
gdb_thread->SetThreadDispatchQAddr(thread_dispatch_qaddr);

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

+3
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,9 @@ class ProcessGDBRemote : public Process,
470470
void DidForkSwitchSoftwareBreakpoints(bool enable);
471471
void DidForkSwitchHardwareTraps(bool enable);
472472

473+
void ParseExpeditedRegisters(ExpeditedRegisterMap &expedited_register_map,
474+
lldb::ThreadSP thread_sp);
475+
473476
// Lists of register fields generated from the remote's target XML.
474477
// Pointers to these RegisterFlags will be set in the register info passed
475478
// back to the upper levels of lldb. Doing so is safe because this class will

0 commit comments

Comments
 (0)