Index: lldb/packages/Python/lldbsuite/test/lldbtest.py =================================================================== --- lldb/packages/Python/lldbsuite/test/lldbtest.py +++ lldb/packages/Python/lldbsuite/test/lldbtest.py @@ -1269,7 +1269,7 @@ return True return False - def isAArch64SVE(self): + def getCPUInfo(self): triple = self.dbg.GetSelectedPlatform().GetTriple() # TODO other platforms, please implement this function @@ -1290,7 +1290,16 @@ except: return False - return " sve " in cpuinfo + return cpuinfo + + def isAArch64SVE(self): + return "sve" in self.getCPUInfo() + + def isAArch64MTE(self): + return "mte" in self.getCPUInfo() + + def isAArch64PAuth(self): + return "paca" in self.getCPUInfo() def hasLinuxVmFlags(self): """ Check that the target machine has "VmFlags" lines in Index: lldb/test/API/commands/register/register/aarch64_dynamic_regset/Makefile =================================================================== --- /dev/null +++ lldb/test/API/commands/register/register/aarch64_dynamic_regset/Makefile @@ -0,0 +1,5 @@ +C_SOURCES := main.c + +CFLAGS_EXTRAS := -march=armv8-a+sve + +include Makefile.rules Index: lldb/test/API/commands/register/register/aarch64_dynamic_regset/TestArm64DynamicRegsets.py =================================================================== --- /dev/null +++ lldb/test/API/commands/register/register/aarch64_dynamic_regset/TestArm64DynamicRegsets.py @@ -0,0 +1,112 @@ +""" +Test AArch64 dynamic register sets +""" + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class RegisterCommandsTestCase(TestBase): + + def check_sve_register_size(self, set, name, expected): + reg_value = set.GetChildMemberWithName(name) + self.assertTrue(reg_value.IsValid(), + 'Verify we have a register named "%s"' % (name)) + self.assertEqual(reg_value.GetByteSize(), expected, + 'Verify "%s" == %i' % (name, expected)) + + def sve_regs_read_dynamic(self, sve_registers): + vg_reg = sve_registers.GetChildMemberWithName("vg") + vg_reg_value = sve_registers.GetChildMemberWithName( + "vg").GetValueAsUnsigned() + + z_reg_size = vg_reg_value * 8 + p_reg_size = int(z_reg_size / 8) + + for i in range(32): + z_regs_value = '{' + \ + ' '.join('0x{:02x}'.format(i + 1) + for _ in range(z_reg_size)) + '}' + self.expect("register read " + 'z%i' % + (i), substrs=[z_regs_value]) + + # Set P registers with random test values. The P registers are predicate + # registers, which hold one bit for each byte available in a Z register. + # For below mentioned values of P registers, P(0,5,10,15) will have all + # Z register lanes set while P(4,9,14) will have no lanes set. + p_value_bytes = ['0xff', '0x55', '0x11', '0x01', '0x00'] + for i in range(16): + p_regs_value = '{' + \ + ' '.join(p_value_bytes[i % 5] for _ in range(p_reg_size)) + '}' + self.expect("register read " + 'p%i' % (i), substrs=[p_regs_value]) + + self.expect("register read ffr", substrs=[p_regs_value]) + + z_regs_value = '{' + \ + ' '.join(('0x9d' for _ in range(z_reg_size))) + '}' + + p_regs_value = '{' + \ + ' '.join(('0xee' for _ in range(p_reg_size))) + '}' + + for i in range(32): + self.runCmd('register write ' + 'z%i' % + (i) + " '" + z_regs_value + "'") + self.expect("register read " + 'z%i' % (i), substrs=[z_regs_value]) + + for i in range(16): + self.runCmd('register write ' + 'p%i' % + (i) + " '" + p_regs_value + "'") + self.expect("register read " + 'p%i' % (i), substrs=[p_regs_value]) + + self.runCmd('register write ' + 'ffr ' + "'" + p_regs_value + "'") + + self.expect("register read " + 'ffr', substrs=[p_regs_value]) + + mydir = TestBase.compute_mydir(__file__) + + @no_debug_info_test + @skipIf(archs=no_match(["aarch64"])) + @skipIf(oslist=no_match(['linux'])) + def test_aarch64_dynamic_regset_config(self): + """Test AArch64 Dynamic Register sets configuration.""" + self.build() + self.line = line_number('main.c', '// Set a break point here.') + + exe = self.getBuildArtifact("a.out") + self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) + + lldbutil.run_break_set_by_file_and_line( + self, "main.c", self.line, num_expected_locations=1) + self.runCmd("run", RUN_SUCCEEDED) + + self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT, + substrs=["stop reason = breakpoint 1."]) + + target = self.dbg.GetSelectedTarget() + process = target.GetProcess() + thread = process.GetThreadAtIndex(0) + currentFrame = thread.GetFrameAtIndex(0) + + for registerSet in currentFrame.GetRegisters(): + if 'Scalable Vector Extension Registers' in registerSet.GetName(): + if not self.isAArch64SVE(): + self.fail( + "LLDB enabled AArch64 SVE register set when it was disabled by target.") + self.sve_regs_read_dynamic(registerSet) + if 'MTE Control Register' in registerSet.GetName(): + if not self.isAArch64MTE(): + self.fail( + "LLDB enabled AArch64 MTE register set when it was disabled by target.") + self.runCmd("register write mte_ctrl 0x7fff9") + self.expect("register read mte_ctrl", + substrs=['mte_ctrl = 0x000000000007fff9']) + if 'Pointer Authentication Registers' in registerSet.GetName(): + if not self.isAArch64PAuth(): + self.fail( + "LLDB enabled AArch64 Pointer Authentication register set when it was disabled by target.") + self.expect("register read data_mask", + substrs=['data_mask = 0x']) + self.expect("register read code_mask", + substrs=['code_mask = 0x']) Index: lldb/test/API/commands/register/register/aarch64_dynamic_regset/main.c =================================================================== --- /dev/null +++ lldb/test/API/commands/register/register/aarch64_dynamic_regset/main.c @@ -0,0 +1,88 @@ +#include +#include + +#ifndef HWCAP2_MTE +#define HWCAP2_MTE (1 << 18) +#endif + +#ifndef HWCAP_PACA +#define HWCAP_PACA (1 << 30) +#endif + +void set_sve_registers() { + // AArch64 SVE extension ISA adds a new set of vector and predicate registers: + // 32 Z registers, 16 P registers, and 1 FFR register. + // Code below populates SVE registers to be read back by the debugger via + // ptrace interface at runtime. + // The P registers are predicate registers and hold one bit for each byte + // available in a Z vector register. For example, an SVE implementation with + // 1024-bit Z registers has 128-bit predicate registers. + // ptrue/pfalse instruction is used to set a predicate lane with a pattern. + // pattern is decided based on size specifier, b, h, s and d. if size + // specified is b all lanes will be set to 1. which is needed to set all bytes + // in a Z registers to the specified value. + asm volatile("setffr\n\t"); + asm volatile("ptrue p0.b\n\t"); + asm volatile("ptrue p1.h\n\t"); + asm volatile("ptrue p2.s\n\t"); + asm volatile("ptrue p3.d\n\t"); + asm volatile("pfalse p4.b\n\t"); + asm volatile("ptrue p5.b\n\t"); + asm volatile("ptrue p6.h\n\t"); + asm volatile("ptrue p7.s\n\t"); + asm volatile("ptrue p8.d\n\t"); + asm volatile("pfalse p9.b\n\t"); + asm volatile("ptrue p10.b\n\t"); + asm volatile("ptrue p11.h\n\t"); + asm volatile("ptrue p12.s\n\t"); + asm volatile("ptrue p13.d\n\t"); + asm volatile("pfalse p14.b\n\t"); + asm volatile("ptrue p15.b\n\t"); + + asm volatile("cpy z0.b, p0/z, #1\n\t"); + asm volatile("cpy z1.b, p5/z, #2\n\t"); + asm volatile("cpy z2.b, p10/z, #3\n\t"); + asm volatile("cpy z3.b, p15/z, #4\n\t"); + asm volatile("cpy z4.b, p0/z, #5\n\t"); + asm volatile("cpy z5.b, p5/z, #6\n\t"); + asm volatile("cpy z6.b, p10/z, #7\n\t"); + asm volatile("cpy z7.b, p15/z, #8\n\t"); + asm volatile("cpy z8.b, p0/z, #9\n\t"); + asm volatile("cpy z9.b, p5/z, #10\n\t"); + asm volatile("cpy z10.b, p10/z, #11\n\t"); + asm volatile("cpy z11.b, p15/z, #12\n\t"); + asm volatile("cpy z12.b, p0/z, #13\n\t"); + asm volatile("cpy z13.b, p5/z, #14\n\t"); + asm volatile("cpy z14.b, p10/z, #15\n\t"); + asm volatile("cpy z15.b, p15/z, #16\n\t"); + asm volatile("cpy z16.b, p0/z, #17\n\t"); + asm volatile("cpy z17.b, p5/z, #18\n\t"); + asm volatile("cpy z18.b, p10/z, #19\n\t"); + asm volatile("cpy z19.b, p15/z, #20\n\t"); + asm volatile("cpy z20.b, p0/z, #21\n\t"); + asm volatile("cpy z21.b, p5/z, #22\n\t"); + asm volatile("cpy z22.b, p10/z, #23\n\t"); + asm volatile("cpy z23.b, p15/z, #24\n\t"); + asm volatile("cpy z24.b, p0/z, #25\n\t"); + asm volatile("cpy z25.b, p5/z, #26\n\t"); + asm volatile("cpy z26.b, p10/z, #27\n\t"); + asm volatile("cpy z27.b, p15/z, #28\n\t"); + asm volatile("cpy z28.b, p0/z, #29\n\t"); + asm volatile("cpy z29.b, p5/z, #30\n\t"); + asm volatile("cpy z30.b, p10/z, #31\n\t"); + asm volatile("cpy z31.b, p15/z, #32\n\t"); +} + +int main() { + unsigned long hwcap = getauxval(AT_HWCAP); + unsigned long hwcap2 = getauxval(AT_HWCAP2); + + unsigned int sve_is_enabled = hwcap & HWCAP_SVE; + unsigned int pauth_is_enabled = hwcap & HWCAP_PACA; + unsigned int mte_is_enabled = hwcap2 & HWCAP2_MTE; + + if (sve_is_enabled) // check if SVE is present + set_sve_registers(); + + return 0; // Set a break point here. +}