Skip to content

Commit 697340e

Browse files
committed
Carefully testing SME and non-SME hardware showed some testsuite issues
TestRegisters.py expected there to be no registers unable to be read. With an SME system when in non-SME mode, all of the SVE/SME registers will show as unreadable. TestGdbRemoteGPacket.py was testing the g/G packet with debugserver (which lldb doesn't use any more) and this exposed the fact that I wasn't handling SME/SVE registers correctly in DNBArchImplArm64::GetRegisterContext/SetRegisterContext. Fix those to correctly account for the size of these register contexts (the ZA register is stored in a vector, instead of having a compile-time register context size). Also, RNBRemote::HandlePacket_G() was not handling the thread specifier properly (it would try to interpret it as content for the packet, and the hex decoding would fail). I think this test might be setting the current thread with Hg<tid> before it sends only "g" or "G", that might work. In debugserver, changed all stack-allocated DNBRegisterValue objects to be unique_ptr managed so they're on heap. This object is now 64k and putting that on the stack could be a problem. We don't have multiple DNBRegisterValue objects alive at the same time, so I didn't dynamically size it to the maximum ZA register size on the current machine. Fix the comment formatting suggestions from Jonas.
1 parent 2e964a4 commit 697340e

File tree

6 files changed

+153
-47
lines changed

6 files changed

+153
-47
lines changed

lldb/test/API/commands/register/register/register_command/TestRegisters.py

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,24 @@ def tearDown(self):
2121
self.dbg.GetSelectedTarget().GetProcess().Destroy()
2222
TestBase.tearDown(self)
2323

24+
# on macOS, detect if the current machine is arm64 and supports SME
25+
def get_sme_available(self):
26+
if self.getArchitecture() != "arm64":
27+
return None
28+
try:
29+
sysctl_output = subprocess.check_output(
30+
["sysctl", "hw.optional.arm.FEAT_SME"]
31+
).decode("utf-8")
32+
except subprocess.CalledProcessError:
33+
return None
34+
m = re.match(r"hw\.optional\.arm\.FEAT_SME: (\w+)", sysctl_output)
35+
if m:
36+
if int(m.group(1)) == 1:
37+
return True
38+
else:
39+
return False
40+
return None
41+
2442
@skipIfiOSSimulator
2543
@skipIf(archs=no_match(["amd64", "arm", "i386", "x86_64"]))
2644
@expectedFailureAll(oslist=["freebsd", "netbsd"], bugnumber="llvm.org/pr48371")
@@ -32,11 +50,19 @@ def test_register_commands(self):
3250
# verify that logging does not assert
3351
self.log_enable("registers")
3452

53+
error_str_matched = False
54+
if self.get_sme_available() == True and self.platformIsDarwin():
55+
# On Darwin AArch64 SME machines, we will have unavailable
56+
# registers when not in Streaming SVE Mode/SME, so
57+
# `register read -a` will report that some registers
58+
# could not be read. This is expected.
59+
error_str_matched = True
60+
3561
self.expect(
3662
"register read -a",
3763
MISSING_EXPECTED_REGISTERS,
3864
substrs=["registers were unavailable"],
39-
matching=False,
65+
matching=error_str_matched,
4066
)
4167

4268
all_registers = self.res.GetOutput()
@@ -60,7 +86,7 @@ def test_register_commands(self):
6086
self.runCmd("register read q15") # may be available
6187

6288
self.expect(
63-
"register read -s 4", substrs=["invalid register set index: 4"], error=True
89+
"register read -s 8", substrs=["invalid register set index: 8"], error=True
6490
)
6591

6692
@skipIfiOSSimulator

lldb/tools/debugserver/source/MacOSX/MachProcess.mm

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1417,15 +1417,17 @@ static uint64_t bits(uint64_t value, uint32_t msbit, uint32_t lsbit) {
14171417
continue;
14181418
for (uint32_t reg = 0; reg < reg_sets[set].num_registers; ++reg) {
14191419
if (strcmp(reg_sets[set].registers[reg].name, "esr") == 0) {
1420-
DNBRegisterValue reg_value;
1421-
if (GetRegisterValue(tid, set, reg, &reg_value)) {
1422-
esr = reg_value.value.uint64;
1420+
std::unique_ptr<DNBRegisterValue> reg_value =
1421+
std::make_unique<DNBRegisterValue>();
1422+
if (GetRegisterValue(tid, set, reg, reg_value.get())) {
1423+
esr = reg_value->value.uint64;
14231424
}
14241425
}
14251426
if (strcmp(reg_sets[set].registers[reg].name, "far") == 0) {
1426-
DNBRegisterValue reg_value;
1427-
if (GetRegisterValue(tid, set, reg, &reg_value)) {
1428-
far = reg_value.value.uint64;
1427+
std::unique_ptr<DNBRegisterValue> reg_value =
1428+
std::make_unique<DNBRegisterValue>();
1429+
if (GetRegisterValue(tid, set, reg, reg_value.get())) {
1430+
far = reg_value->value.uint64;
14291431
}
14301432
}
14311433
}

lldb/tools/debugserver/source/MacOSX/MachThread.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -509,10 +509,12 @@ void MachThread::DumpRegisterState(nub_size_t regSet) {
509509
if (m_arch_up->RegisterSetStateIsValid((int)regSet)) {
510510
const size_t numRegisters = GetNumRegistersInSet(regSet);
511511
uint32_t regIndex = 0;
512-
DNBRegisterValueClass reg;
512+
std::unique_ptr<DNBRegisterValueClass> reg =
513+
std::make_unique<DNBRegisterValueClass>();
513514
for (regIndex = 0; regIndex < numRegisters; ++regIndex) {
514-
if (m_arch_up->GetRegisterValue((uint32_t)regSet, regIndex, &reg)) {
515-
reg.Dump(NULL, NULL);
515+
if (m_arch_up->GetRegisterValue((uint32_t)regSet, regIndex,
516+
reg.get())) {
517+
reg->Dump(NULL, NULL);
516518
}
517519
}
518520
} else {

lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp

Lines changed: 72 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,15 @@ kern_return_t DNBArchMachARM64::GetSVEState(bool force) {
463463
if (!CPUHasSME())
464464
return KERN_INVALID_ARGUMENT;
465465

466+
// If the processor is not in Streaming SVE Mode, these thread_get_states
467+
// will fail, and we may return uninitialized data in the register context.
468+
memset(&m_state.context.sve.z[0], 0,
469+
ARM_SVE_Z_STATE_COUNT * sizeof(uint32_t));
470+
memset(&m_state.context.sve.z[16], 0,
471+
ARM_SVE_Z_STATE_COUNT * sizeof(uint32_t));
472+
memset(&m_state.context.sve.p[0], 0,
473+
ARM_SVE_P_STATE_COUNT * sizeof(uint32_t));
474+
466475
// Read the registers from our thread
467476
mach_msg_type_number_t count = ARM_SVE_Z_STATE_COUNT;
468477
kern_return_t kret =
@@ -502,6 +511,11 @@ kern_return_t DNBArchMachARM64::GetSMEState(bool force) {
502511
if (!CPUHasSME())
503512
return KERN_INVALID_ARGUMENT;
504513

514+
// If the processor is not in Streaming SVE Mode, these thread_get_states
515+
// will fail, and we may return uninitialized data in the register context.
516+
memset(&m_state.context.sme.svcr, 0, ARM_SME_STATE_COUNT * sizeof(uint32_t));
517+
memset(m_state.context.sme.za.data(), 0, m_state.context.sme.za.size());
518+
505519
// Read the registers from our thread
506520
mach_msg_type_number_t count = ARM_SME_STATE_COUNT;
507521
kern_return_t kret =
@@ -539,7 +553,9 @@ kern_return_t DNBArchMachARM64::GetSMEState(bool force) {
539553
}
540554

541555
if (CPUHasSME2()) {
542-
count = ARM_SME2_STATE;
556+
memset(&m_state.context.sme.zt0, 0,
557+
ARM_SME2_STATE_COUNT * sizeof(uint32_t));
558+
count = ARM_SME2_STATE_COUNT;
543559
kret = thread_get_state(m_thread->MachPortNumber(), ARM_SME2_STATE,
544560
(thread_state_t)&m_state.context.sme.zt0, &count);
545561
m_state.SetError(set, Read, kret);
@@ -2903,9 +2919,12 @@ kern_return_t DNBArchMachARM64::GetRegisterState(int set, bool force) {
29032919
case e_regSetALL: {
29042920
kern_return_t retval = GetGPRState(force) | GetVFPState(force) |
29052921
GetEXCState(force) | GetDBGState(force);
2922+
// If the processor is not in Streaming SVE Mode currently, these
2923+
// two will fail to read. Don't return that as an error, it will
2924+
// be the most common case.
29062925
if (CPUHasSME()) {
2907-
retval |= GetSVEState(force);
2908-
retval |= GetSMEState(force);
2926+
GetSVEState(force);
2927+
GetSMEState(force);
29092928
}
29102929
return retval;
29112930
}
@@ -2964,7 +2983,11 @@ nub_size_t DNBArchMachARM64::GetRegisterContext(void *buf, nub_size_t buf_len) {
29642983
const bool cpu_has_sme = CPUHasSME();
29652984
if (cpu_has_sme) {
29662985
size += sizeof(m_state.context.sve);
2967-
size += sizeof(m_state.context.sme);
2986+
// ZA register is in a std::vector<uint8_t> so we need to add
2987+
// the sizes of the SME manually.
2988+
size += ARM_SME_STATE_COUNT * sizeof(uint32_t);
2989+
size += m_state.context.sme.za.size();
2990+
size += ARM_SME2_STATE_COUNT * sizeof(uint32_t);
29682991
}
29692992

29702993
if (buf && buf_len) {
@@ -2974,9 +2997,13 @@ nub_size_t DNBArchMachARM64::GetRegisterContext(void *buf, nub_size_t buf_len) {
29742997
bool force = false;
29752998
if (GetGPRState(force) | GetVFPState(force) | GetEXCState(force))
29762999
return 0;
2977-
if (cpu_has_sme)
2978-
if (GetSVEState(force) | GetSMEState(force))
2979-
return 0;
3000+
// Don't error out if SME/SVE fail to read. These can only be read
3001+
// when the process is in Streaming SVE Mode, so the failure to read
3002+
// them will be common.
3003+
if (cpu_has_sme) {
3004+
GetSVEState(force);
3005+
GetSMEState(force);
3006+
}
29803007

29813008
// Copy each struct individually to avoid any padding that might be between
29823009
// the structs in m_state.context
@@ -2988,8 +3015,17 @@ nub_size_t DNBArchMachARM64::GetRegisterContext(void *buf, nub_size_t buf_len) {
29883015
if (cpu_has_sme) {
29893016
::memcpy(p, &m_state.context.sve, sizeof(m_state.context.sve));
29903017
p += sizeof(m_state.context.sve);
2991-
::memcpy(p, &m_state.context.sme, sizeof(m_state.context.sme));
2992-
p += sizeof(m_state.context.sme);
3018+
3019+
memcpy(p, &m_state.context.sme.svcr,
3020+
ARM_SME_STATE_COUNT * sizeof(uint32_t));
3021+
p += ARM_SME_STATE_COUNT * sizeof(uint32_t);
3022+
memcpy(p, m_state.context.sme.za.data(), m_state.context.sme.za.size());
3023+
p += m_state.context.sme.za.size();
3024+
if (CPUHasSME2()) {
3025+
memcpy(p, &m_state.context.sme.zt0,
3026+
ARM_SME2_STATE_COUNT * sizeof(uint32_t));
3027+
p += ARM_SME2_STATE_COUNT * sizeof(uint32_t);
3028+
}
29933029
}
29943030
::memcpy(p, &m_state.context.exc, sizeof(m_state.context.exc));
29953031
p += sizeof(m_state.context.exc);
@@ -3010,6 +3046,15 @@ nub_size_t DNBArchMachARM64::SetRegisterContext(const void *buf,
30103046
nub_size_t buf_len) {
30113047
nub_size_t size = sizeof(m_state.context.gpr) + sizeof(m_state.context.vfp) +
30123048
sizeof(m_state.context.exc);
3049+
if (CPUHasSME()) {
3050+
// m_state.context.za is three status registers, then a std::vector<uint8_t>
3051+
// for ZA, then zt0, so the size of the data is not statically knowable.
3052+
nub_size_t sme_size = ARM_SME_STATE_COUNT * sizeof(uint32_t);
3053+
sme_size += m_state.context.sme.za.size();
3054+
sme_size += ARM_SME2_STATE_COUNT * sizeof(uint32_t);
3055+
3056+
size += sizeof(m_state.context.sve) + sme_size;
3057+
}
30133058

30143059
if (buf == NULL || buf_len == 0)
30153060
size = 0;
@@ -3025,6 +3070,20 @@ nub_size_t DNBArchMachARM64::SetRegisterContext(const void *buf,
30253070
p += sizeof(m_state.context.gpr);
30263071
::memcpy(&m_state.context.vfp, p, sizeof(m_state.context.vfp));
30273072
p += sizeof(m_state.context.vfp);
3073+
if (CPUHasSME()) {
3074+
memcpy(&m_state.context.sve, p, sizeof(m_state.context.sve));
3075+
p += sizeof(m_state.context.sve);
3076+
memcpy(&m_state.context.sme.svcr, p,
3077+
ARM_SME_STATE_COUNT * sizeof(uint32_t));
3078+
p += ARM_SME_STATE_COUNT * sizeof(uint32_t);
3079+
memcpy(m_state.context.sme.za.data(), p, m_state.context.sme.za.size());
3080+
p += m_state.context.sme.za.size();
3081+
if (CPUHasSME2()) {
3082+
memcpy(&m_state.context.sme.zt0, p,
3083+
ARM_SME2_STATE_COUNT * sizeof(uint32_t));
3084+
p += ARM_SME2_STATE_COUNT * sizeof(uint32_t);
3085+
}
3086+
}
30283087
::memcpy(&m_state.context.exc, p, sizeof(m_state.context.exc));
30293088
p += sizeof(m_state.context.exc);
30303089

@@ -3033,6 +3092,10 @@ nub_size_t DNBArchMachARM64::SetRegisterContext(const void *buf,
30333092
assert(bytes_written == size);
30343093
SetGPRState();
30353094
SetVFPState();
3095+
if (CPUHasSME()) {
3096+
SetSVEState();
3097+
SetSMEState();
3098+
}
30363099
SetEXCState();
30373100
}
30383101
DNBLogThreadedIf(

lldb/tools/debugserver/source/MacOSX/arm64/sme_thread_status.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#include <mach/mach.h>
22
#include <stdint.h>
33

4-
// define the SVE/SME/SME2 thread status structures
4+
// Define the SVE/SME/SME2 thread status structures
55
// flavors, and sizes so this can build against an
66
// older SDK which does not have these definitions
77
// yet.

0 commit comments

Comments
 (0)