mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-28 04:46:07 +00:00
[lldb][Docs] Convert AArch64 Linux doc to Markdown
Executive decision from me given that I am the sole author of the doc and there's nothing Markdown can't handle here.
This commit is contained in:
parent
a131fbf168
commit
f6e771cfed
@ -1,5 +1,4 @@
|
||||
Using LLDB On AArch64 Linux
|
||||
===========================
|
||||
# Using LLDB On AArch64 Linux
|
||||
|
||||
This page explains the details of debugging certain AArch64 extensions using
|
||||
LLDB. If something is not mentioned here, it likely works as you would expect.
|
||||
@ -8,23 +7,21 @@ This is not a replacement for ptrace and Linux Kernel documentation. This covers
|
||||
how LLDB has chosen to use those things and how that effects your experience as
|
||||
a user.
|
||||
|
||||
Scalable Vector Extension (SVE)
|
||||
-------------------------------
|
||||
## Scalable Vector Extension (SVE)
|
||||
|
||||
See `here <https://developer.arm.com/Architectures/Scalable%20Vector%20Extensions>`__
|
||||
to learn about the extension and `here <https://kernel.org/doc/html/latest/arch/arm64/sve.html>`__
|
||||
See [here](https://developer.arm.com/Architectures/Scalable%20Vector%20Extensions)
|
||||
to learn about the extension and [here](https://kernel.org/doc/html/latest/arch/arm64/sve.html)
|
||||
for the Linux Kernel's handling of it.
|
||||
|
||||
In LLDB you will be able to see the following new registers:
|
||||
|
||||
* ``z0-z31`` vector registers, each one has size equal to the vector length.
|
||||
* ``p0-p15`` predicate registers, each one containing 1 bit per byte in the vector
|
||||
* `z0-z31` vector registers, each one has size equal to the vector length.
|
||||
* `p0-p15` predicate registers, each one containing 1 bit per byte in the vector
|
||||
length. Making each one vector length / 8 sized.
|
||||
* ``ffr`` the first fault register, same size as a predicate register.
|
||||
* ``vg``, the vector length in "granules". Each granule is 8 bytes.
|
||||
|
||||
.. code-block::
|
||||
* `ffr` the first fault register, same size as a predicate register.
|
||||
* `vg`, the vector length in "granules". Each granule is 8 bytes.
|
||||
|
||||
```
|
||||
Scalable Vector Extension Registers:
|
||||
vg = 0x0000000000000002
|
||||
z0 = {0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 <...> }
|
||||
@ -32,19 +29,19 @@ In LLDB you will be able to see the following new registers:
|
||||
p0 = {0xff 0xff}
|
||||
<...>
|
||||
ffr = {0xff 0xff}
|
||||
```
|
||||
|
||||
The example above has a vector length of 16 bytes. Within LLDB you will always
|
||||
see "vg" as in the ``vg`` register, which is 2 in this case (8*2 = 16).
|
||||
see "vg" as in the `vg` register, which is 2 in this case (8*2 = 16).
|
||||
Elsewhere in kernel code or applications, you may see "vq" which is the vector
|
||||
length in quadwords (16 bytes). Where you see "vl", it is in bytes.
|
||||
|
||||
While you can count the size of a P or Z register, it is intended that ``vg`` be
|
||||
While you can count the size of a P or Z register, it is intended that `vg` be
|
||||
used to find the current vector length.
|
||||
|
||||
Changing the Vector Length
|
||||
..........................
|
||||
### Changing the Vector Length
|
||||
|
||||
The ``vg`` register can be written during a debug session. Writing the current
|
||||
The `vg` register can be written during a debug session. Writing the current
|
||||
vector length changes nothing. If you increase the vector length, the registers
|
||||
will likely be reset to 0. If you decrease it, LLDB will truncate the Z
|
||||
registers but everything else will be reset to 0.
|
||||
@ -54,21 +51,20 @@ way the same as it was previously. Whether that is done from within the
|
||||
debuggee, or by LLDB. If you need to change the vector length, do so before a
|
||||
function's first use of SVE.
|
||||
|
||||
Z Register Presentation
|
||||
.......................
|
||||
### Z Register Presentation
|
||||
|
||||
LLDB makes no attempt to predict how SVE Z registers will be used. Since LLDB
|
||||
does not know what sort of elements future instructions will interpret the
|
||||
register as. It therefore does not change the visualisation of the register
|
||||
and always defaults to showing a vector of byte sized elements.
|
||||
|
||||
If you know what format you are going to use, give a format option::
|
||||
|
||||
If you know what format you are going to use, give a format option:
|
||||
```
|
||||
(lldb) register read z0 -f uint32_t[]
|
||||
z0 = {0x01010101 0x01010101 0x01010101 0x01010101}
|
||||
```
|
||||
|
||||
FPSIMD and SVE Modes
|
||||
....................
|
||||
### FPSIMD and SVE Modes
|
||||
|
||||
Prior to the debugee's first use of SVE, it is in what the Linux Kernel terms
|
||||
SIMD mode. Only the FPU is being used. In this state LLDB will still show the
|
||||
@ -82,18 +78,16 @@ You can also trigger this with LLDB by writing to an SVE register. Note that
|
||||
there is no way to undo this change from within LLDB. However, the debugee
|
||||
itself could do something to end up back in SIMD mode.
|
||||
|
||||
Expression evaluation
|
||||
.....................
|
||||
### Expression evaluation
|
||||
|
||||
If you evaluate an expression, all SVE state is saved prior to, and restored
|
||||
after the expression has been evaluated. Including the register values and
|
||||
vector length.
|
||||
|
||||
Scalable Matrix Extension (SME)
|
||||
-------------------------------
|
||||
## Scalable Matrix Extension (SME)
|
||||
|
||||
See `here <https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/scalable-matrix-extension-armv9-a-architecture>`__
|
||||
to learn about the extension and `here <https://kernel.org/doc/html/latest/arch/arm64/sme.html>`__
|
||||
See [here](https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/scalable-matrix-extension-armv9-a-architecture)
|
||||
to learn about the extension and [here](https://kernel.org/doc/html/latest/arch/arm64/sme.html)
|
||||
for the Linux Kernel's handling of it.
|
||||
|
||||
SME adds a "Streaming Mode" to SVE, and this mode has its own vector length
|
||||
@ -101,37 +95,38 @@ known as the "Streaming Vector Length".
|
||||
|
||||
In LLDB you will see the following new registers:
|
||||
|
||||
* ``tpidr2``, an extra per thread pointer reserved for use by the SME ABI.
|
||||
* `tpidr2`, an extra per thread pointer reserved for use by the SME ABI.
|
||||
This is not scalable, just pointer sized aka 64 bit.
|
||||
* ``z0-z31`` streaming SVE registers. These have the same names as the
|
||||
* `z0-z31` streaming SVE registers. These have the same names as the
|
||||
non-streaming registers and therefore you will only see the active set in
|
||||
LLDB. You cannot read or write the inactive mode's registers. Their size
|
||||
is the same as the streaming vector length.
|
||||
* ``za`` the Array Storage register. The "Matrix" part of "Scalable Matrix
|
||||
* `za` the Array Storage register. The "Matrix" part of "Scalable Matrix
|
||||
Extension". This is a square made up of rows of length equal to the streaming
|
||||
vector length (svl). Meaning that the total size is svl * svl.
|
||||
* ``svcr`` the Streaming Vector Control Register. This is actually a pseduo
|
||||
register but it matches the content of the architecturaly defined ``SVCR``.
|
||||
* `svcr` the Streaming Vector Control Register. This is actually a pseduo
|
||||
register but it matches the content of the architecturaly defined `SVCR`.
|
||||
This is the register you should use to check whether streaming mode and/or
|
||||
``za`` is active. This register is read only.
|
||||
* ``svg`` the streaming vector length in granules. This value is not connected
|
||||
`za` is active. This register is read only.
|
||||
* `svg` the streaming vector length in granules. This value is not connected
|
||||
to the vector length of non-streaming mode and may change independently. This
|
||||
register is read only.
|
||||
|
||||
.. note::
|
||||
While in non-streaming mode, the ``vg`` register shows the non-streaming
|
||||
vector length, and the ``svg`` register shows the streaming vector length.
|
||||
When in streaming mode, both ``vg`` and ``svg`` show the streaming mode vector
|
||||
```{note}
|
||||
While in non-streaming mode, the `vg` register shows the non-streaming
|
||||
vector length, and the `svg` register shows the streaming vector length.
|
||||
When in streaming mode, both `vg` and `svg` show the streaming mode vector
|
||||
length. Therefore it is not possible at this time to read the non-streaming
|
||||
vector length within LLDB, while in streaming mode. This is a limitation of
|
||||
the LLDB implementation not the architecture, which stores both lengths
|
||||
independently.
|
||||
```
|
||||
|
||||
In the example below, the streaming vector length is 16 bytes and we are in
|
||||
streaming mode. Note that bits 0 and 1 of ``svcr`` are set, indicating that we
|
||||
are in streaming mode and ZA is active. ``vg`` and ``svg`` report the same value
|
||||
as ``vg`` is showing the streaming mode vector length::
|
||||
|
||||
streaming mode. Note that bits 0 and 1 of `svcr` are set, indicating that we
|
||||
are in streaming mode and ZA is active. `vg` and `svg` report the same value
|
||||
as `vg` is showing the streaming mode vector length:
|
||||
```
|
||||
Scalable Vector Extension Registers:
|
||||
vg = 0x0000000000000002
|
||||
z0 = {0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 <...> }
|
||||
@ -150,11 +145,11 @@ as ``vg`` is showing the streaming mode vector length::
|
||||
svg = 0x0000000000000002
|
||||
svcr = 0x0000000000000003
|
||||
za = {0x00 <...> 0x00}
|
||||
```
|
||||
|
||||
Changing the Streaming Vector Length
|
||||
....................................
|
||||
### Changing the Streaming Vector Length
|
||||
|
||||
To reduce complexity for LLDB, ``svg`` is read only. This means that you can
|
||||
To reduce complexity for LLDB, `svg` is read only. This means that you can
|
||||
only change the streaming vector length using LLDB when the debugee is in
|
||||
streaming mode.
|
||||
|
||||
@ -162,80 +157,75 @@ As for non-streaming SVE, doing so will essentially make the content of the SVE
|
||||
registers undefined. It will also disable ZA, which follows what the Linux
|
||||
Kernel does.
|
||||
|
||||
Visibility of an Inactive ZA Register
|
||||
.....................................
|
||||
### Visibility of an Inactive ZA Register
|
||||
|
||||
LLDB does not handle registers that can come and go at runtime (SVE changes
|
||||
size but it does not dissappear). Therefore when ``za`` is not enabled, LLDB
|
||||
size but it does not dissappear). Therefore when `za` is not enabled, LLDB
|
||||
will return a block of 0s instead. This block will match the expected size of
|
||||
``za``::
|
||||
|
||||
`za`:
|
||||
```
|
||||
(lldb) register read za svg svcr
|
||||
za = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 <...> }
|
||||
svg = 0x0000000000000002
|
||||
svcr = 0x0000000000000001
|
||||
```
|
||||
|
||||
Note that ``svcr`` bit 2 is not set, meaning ``za`` is inactive.
|
||||
Note that `svcr` bit 2 is not set, meaning `za` is inactive.
|
||||
|
||||
If you were to write to ``za`` from LLDB, ``za`` will be made active. There is
|
||||
If you were to write to `za` from LLDB, `za` will be made active. There is
|
||||
no way from within LLDB to reverse this change. As for changing the vector
|
||||
length, the debugee could still do something that would disable ``za`` again.
|
||||
length, the debugee could still do something that would disable `za` again.
|
||||
|
||||
If you want to know whether ``za`` is active or not, refer to bit 2 of the
|
||||
``svcr`` register, otherwise known as ``SVCR.ZA``.
|
||||
If you want to know whether `za` is active or not, refer to bit 2 of the
|
||||
`svcr` register, otherwise known as `SVCR.ZA`.
|
||||
|
||||
ZA Register Presentation
|
||||
........................
|
||||
### ZA Register Presentation
|
||||
|
||||
As for SVE, LLDB does not know how the debugee will use ``za``, and therefore
|
||||
As for SVE, LLDB does not know how the debugee will use `za`, and therefore
|
||||
does not know how it would be best to display it. At any time any given
|
||||
instrucion could interpret its contents as many kinds and sizes of data.
|
||||
|
||||
So LLDB will default to showing ``za`` as one large vector of individual bytes.
|
||||
So LLDB will default to showing `za` as one large vector of individual bytes.
|
||||
You can override this with a format option (see the SVE example above).
|
||||
|
||||
Expression Evaluation
|
||||
.....................
|
||||
### Expression Evaluation
|
||||
|
||||
The mode (streaming or non-streaming), streaming vector length and ZA state will
|
||||
be restored after expression evaluation. On top of all the things saved for SVE
|
||||
in general.
|
||||
|
||||
Scalable Matrix Extension (SME2)
|
||||
--------------------------------
|
||||
## Scalable Matrix Extension (SME2)
|
||||
|
||||
The Scalable Matrix Extension 2 is documented in the same architecture
|
||||
specification as SME, and covered by the same kernel documentation page as SME.
|
||||
|
||||
SME2 adds 1 new register, ``zt0``. This register is a fixed size 512 bit
|
||||
SME2 adds 1 new register, `zt0`. This register is a fixed size 512 bit
|
||||
register that is used by new instructions added in SME2. It is shown in LLDB in
|
||||
the existing SME register set.
|
||||
|
||||
``zt0`` can be active or inactive, as ``za`` can. The same ``SVCR.ZA`` bit
|
||||
controls this. An inactive ``zt0`` is shown as 0s, like ``za`` is. Though in
|
||||
``zt0``'s case, LLDB does not need to fake the value. Ptrace already returns a
|
||||
block of 0s for an inactive ``zt0``.
|
||||
`zt0` can be active or inactive, as `za` can. The same `SVCR.ZA` bit
|
||||
controls this. An inactive `zt0` is shown as 0s, like `za` is. Though in
|
||||
`zt0`'s case, LLDB does not need to fake the value. Ptrace already returns a
|
||||
block of 0s for an inactive `zt0`.
|
||||
|
||||
Like ``za``, writing to an inactive ``zt0`` will enable it and ``za``. This can
|
||||
be done from within LLDB. If the write is instead to ``za``, ``zt0`` becomes
|
||||
Like `za`, writing to an inactive `zt0` will enable it and `za`. This can
|
||||
be done from within LLDB. If the write is instead to `za`, `zt0` becomes
|
||||
active but with a value of all 0s.
|
||||
|
||||
Since ``svcr`` is read only, there is no way at this time to deactivate the
|
||||
Since `svcr` is read only, there is no way at this time to deactivate the
|
||||
registers from within LLDB (though of course a running process can still do
|
||||
this).
|
||||
|
||||
To check whether ``zt0`` is active, refer to ``SVCR.ZA`` and not to the value of
|
||||
``zt0``.
|
||||
To check whether `zt0` is active, refer to `SVCR.ZA` and not to the value of
|
||||
`zt0`.
|
||||
|
||||
ZT0 Register Presentation
|
||||
.........................
|
||||
### ZT0 Register Presentation
|
||||
|
||||
As for ``za``, the meaning of ``zt0`` depends on the instructions used with it,
|
||||
As for `za`, the meaning of `zt0` depends on the instructions used with it,
|
||||
so LLDB does not attempt to guess this and defaults to showing it as a vector of
|
||||
bytes.
|
||||
|
||||
Expression Evaluation
|
||||
.....................
|
||||
### Expression Evaluation
|
||||
|
||||
``zt0``'s value and whether it is active or not will be saved prior to
|
||||
`zt0`'s value and whether it is active or not will be saved prior to
|
||||
expression evaluation and restored afterwards.
|
Loading…
x
Reference in New Issue
Block a user