llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
29.42k stars 12.15k forks source link

lldb cannot read AArch64 FPU (Neon) registers from qemu when SVE is enabled #107864

Closed DavidSpickett closed 2 months ago

DavidSpickett commented 2 months ago
$ qemu-aarch64 -g 1234 /tmp/test.o

$ ./bin/lldb /tmp/test.o -o "log enable gdb-remote packets" -o "gdb-remote 1234"
<...>
(lldb) register read --all
<...>
general:
        x0 = 0x0000000000000000
<...>
  pauth_cmask_high = 0xffff000000000000
32 registers were unavailable.
(lldb) register read v0
error: Invalid register name 'v0'.

GDB 12.1 (only version I checked) does not list the registers in info registers but it will let you read it individually:

(gdb) info register v0
v0             {d = {f = {0x0, 0x0}, u = {0x0, 0x0}, s = {0x0, 0x0}}, s = {f = <...>

If I choose a CPU without SVE, the problem is fixed:

$ qemu-aarch64 -g 1234 -cpu cortex-a53 /tmp/test.o

(lldb) register read --all
general:
<...>
        v0 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}
<...>
       v31 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}
      fpsr = 0x00000000
      fpcr = 0x00000000

(lldb) register read v0
      v0 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}

This is because QEMU does not send info about the floating point registers if SVE is enabled. On the grounds that we should know that we can just extract them from the bottom 128 bits of the SVE registers.

I might have argued that that's exactly what the XML is supposed to inform us about, but ok, that ship has sailed.

https://gitlab.com/qemu-project/qemu/-/blob/master/target/arm/gdbstub.c?ref_type=heads#L512

        /*
         * The lower part of each SVE register aliases to the FPU
         * registers so we don't need to include both.
         */

QEMU sends us XML like this:

<?xml version="1.0"?><!DOCTYPE target SYSTEM "gdb-target.dtd">
<target>
<architecture>aarch64</architecture>
<xi:include href="aarch64-core.xml"/>
<xi:include href="sve-registers.xml"/>
<xi:include href="aarch64-pauth.xml"/>
<xi:include href="system-registers.xml"/>
</target>

The SVE contents are:

<?xml version="1.0"?>
<!DOCTYPE feature SYSTEM "gdb-target.dtd">
<feature name="org.gnu.gdb.aarch64.sve">
  <...>
  <reg name="z0" bitsize="2048" regnum="34" type="svev"/>
  <...>
  <reg name="fpsr" bitsize="32" regnum="66" type="int" group="float"/>
  <reg name="fpcr" bitsize="32" regnum="67" type="int" group="float"/>
  <reg name="p0" bitsize="256" regnum="68" type="svep"/>
  <...>
  <reg name="ffr" bitsize="256" regnum="84" type="svep" group="vector"/>
  <reg name="vg" bitsize="64" regnum="85" type="int"/>
</feature>

It does not include specific entries for v0 and the other FPU registers.

Clearly lldb knows there are 32 other registers (v0-31) that we expect to get, so some fallback code is being executed. It just doesn't know where to get the values from. We'll have to teach that to use the SVE values.

llvmbot commented 2 months ago

@llvm/issue-subscribers-lldb

Author: David Spickett (DavidSpickett)

``` $ qemu-aarch64 -g 1234 /tmp/test.o $ ./bin/lldb /tmp/test.o -o "log enable gdb-remote packets" -o "gdb-remote 1234" <...> (lldb) register read --all <...> general: x0 = 0x0000000000000000 <...> pauth_cmask_high = 0xffff000000000000 32 registers were unavailable. (lldb) register read v0 error: Invalid register name 'v0'. ``` GDB 12.1 (only version I checked) does not list the registers in `info registers` but it will let you read it individually: ``` (gdb) info register v0 v0 {d = {f = {0x0, 0x0}, u = {0x0, 0x0}, s = {0x0, 0x0}}, s = {f = <...> ``` If I choose a CPU without SVE, the problem is fixed: ``` $ qemu-aarch64 -g 1234 -cpu cortex-a53 /tmp/test.o (lldb) register read --all general: <...> v0 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00} <...> v31 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00} fpsr = 0x00000000 fpcr = 0x00000000 (lldb) register read v0 v0 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00} ``` This is because QEMU does not send info about the floating point registers if SVE is enabled. On the grounds that we should know that we can just extract them from the bottom 128 bits of the SVE registers. I might have argued that that's exactly what the XML is supposed to inform us about, but ok, that ship has sailed. https://gitlab.com/qemu-project/qemu/-/blob/master/target/arm/gdbstub.c?ref_type=heads#L512 ``` /* * The lower part of each SVE register aliases to the FPU * registers so we don't need to include both. */ ``` QEMU sends us XML like this: ``` <?xml version="1.0"?><!DOCTYPE target SYSTEM "gdb-target.dtd"> <target> <architecture>aarch64</architecture> <xi:include href="aarch64-core.xml"/> <xi:include href="sve-registers.xml"/> <xi:include href="aarch64-pauth.xml"/> <xi:include href="system-registers.xml"/> </target> ``` The SVE contents are: ``` <?xml version="1.0"?> <!DOCTYPE feature SYSTEM "gdb-target.dtd"> <feature name="org.gnu.gdb.aarch64.sve"> <...> <reg name="z0" bitsize="2048" regnum="34" type="svev"/> <...> <reg name="fpsr" bitsize="32" regnum="66" type="int" group="float"/> <reg name="fpcr" bitsize="32" regnum="67" type="int" group="float"/> <reg name="p0" bitsize="256" regnum="68" type="svep"/> <...> <reg name="ffr" bitsize="256" regnum="84" type="svep" group="vector"/> <reg name="vg" bitsize="64" regnum="85" type="int"/> </feature> ``` It does not include specific entries for `v0` and the other FPU registers. Clearly lldb knows there are 32 other registers (v0-31) that we expect to get, so some fallback code is being executed. It just doesn't know where to get the values from. We'll have to teach that to use the SVE values.
DavidSpickett commented 2 months ago

Friendly neighborhood GDB maintainer points out that I need to use info all-registers or info registers vector and then I'd see them in the output.

Either way, GDB knows how to get the V register values.