| """ Check that when a debug server provides XML that only defines SVE Z registers, | |
| and does not include Neon V registers, lldb creates sub-registers to represent | |
| the V registers as the bottom 128 bits of the Z registers. | |
| qemu-aarch64 is one such debug server. | |
| This also doubles as a test that lldb has a fallback path for registers of | |
| unknown type that are > 128 bits, as the SVE registers are here. | |
| """ | |
| from textwrap import dedent | |
| import lldb | |
| from lldbsuite.test.lldbtest import * | |
| from lldbsuite.test.decorators import * | |
| from lldbsuite.test.gdbclientutils import * | |
| from lldbsuite.test.lldbgdbclient import GDBRemoteTestBase | |
| class Responder(MockGDBServerResponder): | |
| def __init__(self): | |
| super().__init__() | |
| self.vg = 4 | |
| self.pc = 0xA0A0A0A0A0A0A0A0 | |
| def qXferRead(self, obj, annex, offset, length): | |
| if annex == "target.xml": | |
| # Note that QEMU sends the current SVE size in XML and the debugger | |
| # then reads vg to know the latest size. | |
| return ( | |
| dedent( | |
| """\ | |
| <?xml version="1.0"?> | |
| <target version="1.0"> | |
| <architecture>aarch64</architecture> | |
| <feature name="org.gnu.gdb.aarch64.core"> | |
| <reg name="pc" regnum="0" bitsize="64"/> | |
| <reg name="vg" regnum="1" bitsize="64"/> | |
| <reg name="z0" regnum="2" bitsize="2048" type="not_a_type"/> | |
| </feature> | |
| </target>""" | |
| ), | |
| False, | |
| ) | |
| return (None,) | |
| def readRegister(self, regnum): | |
| return "E01" | |
| def readRegisters(self): | |
| return "".join( | |
| [ | |
| # 64 bit PC. | |
| f"{self.pc:x}", | |
| # 64 bit vg | |
| f"0{self.vg}00000000000000", | |
| # Enough data for 256 and 512 bit SVE. | |
| "".join([f"{n:02x}" * 4 for n in range(1, 17)]), | |
| ] | |
| ) | |
| def cont(self): | |
| # vg is expedited so that lldb can resize the SVE registers. | |
| return f"T02thread:1ff0d;threads:1ff0d;thread-pcs:{self.pc};01:0{self.vg}00000000000000;" | |
| def writeRegisters(self, registers_hex): | |
| # We get a block of data containing values in regnum order. | |
| self.vg = int(registers_hex[16:18]) | |
| return "OK" | |
| class TestXMLRegisterFlags(GDBRemoteTestBase): | |
| def check_regs(self, vg): | |
| # Each 32 bit chunk repeats n. | |
| z0_value = " ".join( | |
| [" ".join([f"0x{n:02x}"] * 4) for n in range(1, (vg * 2) + 1)] | |
| ) | |
| self.expect( | |
| "register read vg z0 v0 s0 d0", | |
| substrs=[ | |
| f" vg = 0x000000000000000{vg}\n" | |
| " z0 = {" + z0_value + "}\n" | |
| " v0 = {0x01 0x01 0x01 0x01 0x02 0x02 0x02 0x02 0x03 0x03 0x03 0x03 0x04 0x04 0x04 0x04}\n" | |
| " s0 = 2.36942783E-38\n" | |
| " d0 = 5.3779407333977203E-299\n" | |
| ], | |
| ) | |
| self.expect("register read s0 --format uint32", substrs=["s0 = {0x01010101}"]) | |
| self.expect( | |
| "register read d0 --format uint64", | |
| substrs=["d0 = {0x0202020201010101}"], | |
| ) | |
| @skipIfXmlSupportMissing | |
| @skipIfRemote | |
| @skipIfLLVMTargetMissing("AArch64") | |
| def test_v_sub_registers(self): | |
| self.server.responder = Responder() | |
| target = self.dbg.CreateTarget("") | |
| if self.TraceOn(): | |
| self.runCmd("log enable gdb-remote packets") | |
| self.addTearDownHook(lambda: self.runCmd("log disable gdb-remote packets")) | |
| process = self.connect(target) | |
| lldbutil.expect_state_changes( | |
| self, self.dbg.GetListener(), process, [lldb.eStateStopped] | |
| ) | |
| self.check_regs(4) | |
| # Now increase the SVE length and continue. The mock will respond with a new | |
| # vg and lldb will reconfigure the register defs. This should not break the | |
| # sub-registers. | |
| self.runCmd("register write vg 8") | |
| self.expect("continue", substrs=["stop reason = signal SIGINT"]) | |
| self.check_regs(8) |