Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,25 @@ bool ArchitectureAArch64::ReconfigureRegisterInfo(DynamicRegisterInfo &reg_info,
if (reg_value != fail_value && reg_value <= 32)
svg_reg_value = reg_value;
}
if (!svg_reg_value) {
const RegisterInfo *darwin_svg_reg_info = reg_info.GetRegisterInfo("svl");
if (darwin_svg_reg_info) {
uint32_t svg_reg_num = darwin_svg_reg_info->kinds[eRegisterKindLLDB];
uint64_t reg_value =
reg_context.ReadRegisterAsUnsigned(svg_reg_num, fail_value);
// UpdateARM64SVERegistersInfos and UpdateARM64SMERegistersInfos
// expect the number of 8-byte granules; darwin provides number of
// bytes.
if (reg_value != fail_value && reg_value <= 256) {
svg_reg_value = reg_value / 8;
// Apple hardware only implements Streaming SVE mode, so
// the non-streaming Vector Length is not reported by the
// kernel. Set both svg and vg to this svl value.
if (!vg_reg_value)
vg_reg_value = reg_value / 8;
Comment on lines +112 to +118
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: lots of magic values here but in all fairness that's consistent with the surrounding code. The comment covers the 8 byte granule so I'm not too concerned, though some constants might make this easier to read.

}
}
}

if (!vg_reg_value && !svg_reg_value)
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,24 @@ def tearDown(self):
self.dbg.GetSelectedTarget().GetProcess().Destroy()
TestBase.tearDown(self)

# on macOS, detect if the current machine is arm64 and supports SME
def get_sme_available(self):
if self.getArchitecture() != "arm64":
return None
try:
sysctl_output = subprocess.check_output(
["sysctl", "hw.optional.arm.FEAT_SME"]
).decode("utf-8")
except subprocess.CalledProcessError:
return None
m = re.match(r"hw\.optional\.arm\.FEAT_SME: (\w+)", sysctl_output)
if m:
if int(m.group(1)) == 1:
return True
else:
return False
return None

@skipIfiOSSimulator
@skipIf(archs=no_match(["amd64", "arm", "i386", "x86_64"]))
@expectedFailureAll(oslist=["freebsd", "netbsd"], bugnumber="llvm.org/pr48371")
Expand All @@ -32,11 +50,19 @@ def test_register_commands(self):
# verify that logging does not assert
self.log_enable("registers")

error_str_matched = False
if self.get_sme_available() == True and self.platformIsDarwin():
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if self.get_sme_available() == True and self.platformIsDarwin():
if self.get_sme_available() and self.platformIsDarwin():

# On Darwin AArch64 SME machines, we will have unavailable
# registers when not in Streaming SVE Mode/SME, so
# `register read -a` will report that some registers
# could not be read. This is expected.
error_str_matched = True

self.expect(
"register read -a",
MISSING_EXPECTED_REGISTERS,
substrs=["registers were unavailable"],
matching=False,
matching=error_str_matched,
)

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

self.expect(
"register read -s 4", substrs=["invalid register set index: 4"], error=True
"register read -s 8", substrs=["invalid register set index: 8"], error=True
)

@skipIfiOSSimulator
Expand Down
5 changes: 5 additions & 0 deletions lldb/test/API/macosx/sme-registers/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
C_SOURCES := main.c

CFLAGS_EXTRAS := -mcpu=apple-m4

include Makefile.rules
217 changes: 217 additions & 0 deletions lldb/test/API/macosx/sme-registers/TestSMERegistersDarwin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
import lldb
from lldbsuite.test.lldbtest import *
from lldbsuite.test.decorators import *
import lldbsuite.test.lldbutil as lldbutil
import os


class TestSMERegistersDarwin(TestBase):
NO_DEBUG_INFO_TESTCASE = True
mydir = TestBase.compute_mydir(__file__)

@skipIfRemote
@skipUnlessDarwin
@skipUnlessFeature("hw.optional.arm.FEAT_SME")
@skipUnlessFeature("hw.optional.arm.FEAT_SME2")
# thread_set_state/thread_get_state only avail in macOS 15.4+
@skipIf(macos_version=["<", "15.4"])
def test(self):
"""Test that we can read the contents of the SME/SVE registers on Darwin"""
self.build()
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
self, "break before sme", lldb.SBFileSpec("main.c")
)
frame = thread.GetFrameAtIndex(0)
self.assertTrue(frame.IsValid())

self.assertTrue(
target.BreakpointCreateBySourceRegex(
"break while sme", lldb.SBFileSpec("main.c")
).IsValid()
)
self.assertTrue(
target.BreakpointCreateBySourceRegex(
"break after sme", lldb.SBFileSpec("main.c")
).IsValid()
)

if self.TraceOn():
self.runCmd("reg read -a")

self.assertTrue(frame.register["svl"].GetError().Fail())
self.assertTrue(frame.register["z0"].GetError().Fail())
self.assertTrue(frame.register["p0"].GetError().Fail())
self.assertTrue(frame.register["za"].GetError().Fail())
self.assertTrue(frame.register["zt0"].GetError().Fail())

process.Continue()
frame = thread.GetFrameAtIndex(0)
self.assertEqual(thread.GetStopReason(), lldb.eStopReasonBreakpoint)

# Now in SME enabled mode
self.assertTrue(frame.register["svl"].GetError().Success())
self.assertTrue(frame.register["z0"].GetError().Success())
self.assertTrue(frame.register["p0"].GetError().Success())
self.assertTrue(frame.register["za"].GetError().Success())
self.assertTrue(frame.register["zt0"].GetError().Success())

# SSVE and SME modes should be enabled (reflecting PSTATE.SM and PSTATE.ZA)
svcr = frame.register["svcr"]
self.assertEqual(svcr.GetValueAsUnsigned(), 3)

svl_reg = frame.register["svl"]
svl = svl_reg.GetValueAsUnsigned()

z0 = frame.register["z0"]
self.assertEqual(z0.GetNumChildren(), svl)
self.assertEqual(z0.GetChildAtIndex(0).GetValueAsUnsigned(), 0x1)
self.assertEqual(z0.GetChildAtIndex(svl - 1).GetValueAsUnsigned(), 0x1)

z31 = frame.register["z31"]
self.assertEqual(z31.GetNumChildren(), svl)
self.assertEqual(z31.GetChildAtIndex(0).GetValueAsUnsigned(), 32)
self.assertEqual(z31.GetChildAtIndex(svl - 1).GetValueAsUnsigned(), 32)

p0 = frame.register["p0"]
self.assertEqual(p0.GetNumChildren(), svl / 8)
self.assertEqual(p0.GetChildAtIndex(0).GetValueAsUnsigned(), 0xFF)
self.assertEqual(
p0.GetChildAtIndex(p0.GetNumChildren() - 1).GetValueAsUnsigned(), 0xFF
)

p15 = frame.register["p15"]
self.assertEqual(p15.GetNumChildren(), svl / 8)
self.assertEqual(p15.GetChildAtIndex(0).GetValueAsUnsigned(), 0xFF)
self.assertEqual(
p15.GetChildAtIndex(p15.GetNumChildren() - 1).GetValueAsUnsigned(), 0xFF
)

za = frame.register["za"]
self.assertEqual(za.GetNumChildren(), (svl * svl))
za_0 = za.GetChildAtIndex(0)
self.assertEqual(za_0.GetValueAsUnsigned(), 4)
za_final = za.GetChildAtIndex(za.GetNumChildren() - 1)
self.assertEqual(za_final.GetValueAsUnsigned(), 67)

zt0 = frame.register["zt0"]
self.assertEqual(zt0.GetNumChildren(), 64)
zt0_0 = zt0.GetChildAtIndex(0)
self.assertEqual(zt0_0.GetValueAsUnsigned(), 0)
zt0_final = zt0.GetChildAtIndex(63)
self.assertEqual(zt0_final.GetValueAsUnsigned(), 63)

# Modify all of the registers, instruction step, confirm that the
# registers have the new values. Without the instruction step, it's
# possible debugserver or lldb could lie about the write succeeding.

z0_old_values = []
z0_new_values = []
z0_new_str = '"{'
for i in range(svl):
z0_old_values.append(z0.GetChildAtIndex(i).GetValueAsUnsigned())
z0_new_values.append(z0_old_values[i] + 5)
z0_new_str = z0_new_str + ("0x%02x " % z0_new_values[i])
z0_new_str = z0_new_str + '}"'
self.runCmd("reg write z0 %s" % z0_new_str)

z31_old_values = []
z31_new_values = []
z31_new_str = '"{'
for i in range(svl):
z31_old_values.append(z31.GetChildAtIndex(i).GetValueAsUnsigned())
z31_new_values.append(z31_old_values[i] + 3)
z31_new_str = z31_new_str + ("0x%02x " % z31_new_values[i])
z31_new_str = z31_new_str + '}"'
self.runCmd("reg write z31 %s" % z31_new_str)

p0_old_values = []
p0_new_values = []
p0_new_str = '"{'
for i in range(int(svl / 8)):
p0_old_values.append(p0.GetChildAtIndex(i).GetValueAsUnsigned())
p0_new_values.append(p0_old_values[i] - 5)
p0_new_str = p0_new_str + ("0x%02x " % p0_new_values[i])
p0_new_str = p0_new_str + '}"'
self.runCmd("reg write p0 %s" % p0_new_str)

p15_old_values = []
p15_new_values = []
p15_new_str = '"{'
for i in range(int(svl / 8)):
p15_old_values.append(p15.GetChildAtIndex(i).GetValueAsUnsigned())
p15_new_values.append(p15_old_values[i] - 8)
p15_new_str = p15_new_str + ("0x%02x " % p15_new_values[i])
p15_new_str = p15_new_str + '}"'
self.runCmd("reg write p15 %s" % p15_new_str)

za_old_values = []
za_new_values = []
za_new_str = '"{'
for i in range(svl * svl):
za_old_values.append(za.GetChildAtIndex(i).GetValueAsUnsigned())
za_new_values.append(za_old_values[i] + 7)
za_new_str = za_new_str + ("0x%02x " % za_new_values[i])
za_new_str = za_new_str + '}"'
self.runCmd("reg write za %s" % za_new_str)

zt0_old_values = []
zt0_new_values = []
zt0_new_str = '"{'
for i in range(64):
zt0_old_values.append(zt0.GetChildAtIndex(i).GetValueAsUnsigned())
zt0_new_values.append(zt0_old_values[i] + 2)
zt0_new_str = zt0_new_str + ("0x%02x " % zt0_new_values[i])
zt0_new_str = zt0_new_str + '}"'
self.runCmd("reg write zt0 %s" % zt0_new_str)

thread.StepInstruction(False)
frame = thread.GetFrameAtIndex(0)

if self.TraceOn():
self.runCmd("reg read -a")

z0 = frame.register["z0"]
for i in range(z0.GetNumChildren()):
self.assertEqual(
z0_new_values[i], z0.GetChildAtIndex(i).GetValueAsUnsigned()
)

z31 = frame.register["z31"]
for i in range(z31.GetNumChildren()):
self.assertEqual(
z31_new_values[i], z31.GetChildAtIndex(i).GetValueAsUnsigned()
)

p0 = frame.register["p0"]
for i in range(p0.GetNumChildren()):
self.assertEqual(
p0_new_values[i], p0.GetChildAtIndex(i).GetValueAsUnsigned()
)

p15 = frame.register["p15"]
for i in range(p15.GetNumChildren()):
self.assertEqual(
p15_new_values[i], p15.GetChildAtIndex(i).GetValueAsUnsigned()
)

za = frame.register["za"]
for i in range(za.GetNumChildren()):
self.assertEqual(
za_new_values[i], za.GetChildAtIndex(i).GetValueAsUnsigned()
)

zt0 = frame.register["zt0"]
for i in range(zt0.GetNumChildren()):
self.assertEqual(
zt0_new_values[i], zt0.GetChildAtIndex(i).GetValueAsUnsigned()
)

process.Continue()
frame = thread.GetFrameAtIndex(0)
self.assertEqual(thread.GetStopReason(), lldb.eStopReasonBreakpoint)

self.assertTrue(frame.register["svl"].GetError().Fail())
self.assertTrue(frame.register["z0"].GetError().Fail())
self.assertTrue(frame.register["p0"].GetError().Fail())
self.assertTrue(frame.register["za"].GetError().Fail())
self.assertTrue(frame.register["zt0"].GetError().Fail())
Loading
Loading