[RFC] DW_OP_piece vs. DW_OP_bit_piece on a Register

Andreas Arnez
2016-01-14T16:34:37Z

The following is mainly targeted at readers with a strong DWARF
background. Anybody else may read for interest/amusement or safely
ignore.

After analyzing some test case failures in GCC and GDB I realized that
there are various problems with the handling of DWARF pieces
(particularly from registers) in the current implementations of GCC and
GDB. I'm working on a fix for the GDB part, but first I'd like to check
whether I'm heading into the right direction -- or what the right
direction is supposed to be. The article below outlines these issues
and the suggested solution options.

Any kind of feedback is greatly appreciated!

--
Andreas

-- >8 --
_______________________________________________

DW_OP_PIECE VS. DW_OP_BIT_PIECE ON A REGISTER

Andreas Arnez
_______________________________________________

<2016-01-14 Thu>

Table of Contents
_________________

1 Overview
2 Example Scenarios
.. 2.1 z/Architecture Floating-Point- and Vector Registers
.. 2.2 SPU Preferred Slot
3 Current State And Issues
.. 3.1 DW_OP_bit_piece on a Register
..... 3.1.1 DWARF Definition of DW_OP_bit_piece
..... 3.1.2 Current GCC Usage of DW_OP_bit_piece
..... 3.1.3 Current GDB Handling of DW_OP_bit_piece
.. 3.2 DW_OP_piece on a Register
..... 3.2.1 DWARF Definition of DW_OP_piece
..... 3.2.2 Current GCC Usage of DW_OP_piece
..... 3.2.3 Current GDB Handling of DW_OP_piece
4 Options
.. 4.1 Literal Interpretation
..... 4.1.1 Discussion
.. 4.2 Loose Interpretation
..... 4.2.1 Discussion
.. 4.3 Same Scheme for Bit- and Byte Pieces
..... 4.3.1 Discussion
5 Padding
.. 5.1 Stack Values
.. 5.2 Registers
.. 5.3 Padding: Options
..... 5.3.1 No padding support
..... 5.3.2 Padding support for integer stack values
..... 5.3.3 Padding support for stack values and registers
6 Summary of Open Questions

1 Overview
==========

While trying to fix various problems with the handling of DWARF pieces
in GDB, it turned out that there are some inconsistencies between the
DWARF standard on one hand and the handling in GCC and GDB on the
other hand.

Questions that came up include: Which of a register's bits are
designated by the DW_OP_piece and DW_OP_bit_piece operations? What
does the DWARF standard say? How does GCC currently use these
operations? What do we actually want?

2 Example Scenarios
===================

Scenarios involving DWARF pieces are probably more interesting on
big-endian platforms. Consider the following examples.

2.1 z/Architecture Floating-Point- and Vector Registers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

While the general (integer) registers on z/Architecture have a fairly
strong natural right-alignment, this is not true for floating point
registers and vector registers. Instead, the following holds:
- Values are usually left-aligned in floating-point registers.
- Each 64-bit floating-point register is embedded left-aligned in a
128-bit vector register, and both have the same DWARF register
number.

,----
| :<-- FP Register -->:
| : :
| : float :
| +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| |///|///|///|///| | | | | | | | | | | | |
| +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| |///|///|///|///|///|///|///|///| | | | | | | | |
| +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| double
`----

Now consider a pieced object with one of its pieces residing in a
floating-point register. If represented as a piece of the respective
vector register, which offset should be used for DW_OP_bit_piece? Can
DW_OP_piece be used?

Or consider multiple variables which are scheduled into a single
vector register, due to straight-line vectorization. How should the
locations of these variables be represented in DWARF?

2.2 SPU Preferred Slot
~~~~~~~~~~~~~~~~~~~~~~

SPU registers have a "preferred slot" for storing scalar values of a
particular size:
,----
| char
| +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| | 0 | | |///| | | | | 8 | | | | | | | 15|
| +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
| short
| +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| | | |///|///| | | | | | | | | | | | |
| +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
| int
| +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| |///|///|///|///| | | | | | | | | | | | |
| +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
| long long
| +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| |///|///|///|///|///|///|///|///| | | | | | | | |
| +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
`----
The DWARF location of such a scalar value would typically be described
with DW_OP_reg<n> or DW_OP_regx, without a piece operation. It is
then up to the debugger to determine the placement of the value within
the register. In GDB this is implemented with the gdbarch method
`value_from_register'.

Now, how do the DWARF piece operations relate to these preferred
slots?

3 Current State And Issues
==========================

GCC and GDB currently have various problems and inconsistencies in
their usage and handling of DW_OP_bit_piece and DW_OP_piece.
Additionally, this area may be a bit under-specified in the DWARF
standard. The following sections give an overview of the current
state.

3.1 DW_OP_bit_piece on a Register
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

DW_OP_bit_piece has been added to DWARF as a more general way of
describing pieces than DW_OP_piece. However, after its introduction
in DWARF-3, it was supported neither by GCC nor GDB for quite some
time, and its support is still incomplete and widely broken.

3.1.1 DWARF Definition of DW_OP_bit_piece
-----------------------------------------

The standard says: "If the location is a register, the offset is from
the least significant bit end of the register."

* 3.1.1.1 Which is a register's "least significant bit"?

Some clarification may be needed here. For instance, consider a
register that can naturally hold various-sized integers, but with
their least significant bits at different positions, such as an SPU
register. Or consider a vector register that can not naturally hold a
single full-size integer.

Maybe, assuming that each register has some defined byte order, the
least significant bit refers to the appropriate bit in the register's
first or last byte, for little- or big-endian targets, respectively.
In other words, bit pieces with offset 0 would be taken from the left
on little-endian targets and from the right on big-endian targets.

Note that this definition precludes "register growth" beyond the right
end in future versions of a big-endian architecture, such as with the
floating point registers on z, when they were extended to vector
registers. On the other hand, extending an integer register from 32
to 64 bit (or more) would work nicely.

Also note that this definition implies opposite bit ordering on
typical big-endian targets for register- versus memory locations. For
the latter the DWARF standard requests "using the bit numbering and
direction conventions that are appropriate to the current language on
the target system". And on big-endian targets this typically means
MSB0 bit order.

* 3.1.1.2 What is the rationale for this definition?

It is not obvious why DW_OP_bit_piece is defined differently for
registers as for memory locations. One possible reason may be to
allow appropriate register growth, but that goal is not met either, as
illustrated by the example in 2.1. Is there some other rationale?

3.1.2 Current GCC Usage of DW_OP_bit_piece
------------------------------------------

GCC seems to generate DW_OP_bit_piece only for variables that have
been optimized by SRA, in `dw_sra_loc_expr'. For register locations
the piece offset is then always zero.

However, if the offset is zero and the size is a multiple of 8,
DW_OP_bit_piece is not actually used, but DW_OP_piece is emitted
instead, obviously under the assumption that this is a shorter way of
describing the same piece. Such "simplification" logic can be found
in LLVM as well.

GCC does not seem to emit DW_OP_bit_piece for multiple variables
residing in a single vector register. Instead, no DWARF location is
emitted at all for these variables.

3.1.3 Current GDB Handling of DW_OP_bit_piece
---------------------------------------------

GDB interprets the offset and size of DW_OP_bit_piece for registers as
suggested above: Bit pieces are taken from the right on big-endian
targets, and from the left on little-endian targets.

However, the implementation in GDB has various issues that often lead
to incorrect results when trying to access bit pieces. For instance,
when the bit size is not a multiple of 8, GDB usually corrupts the
result. Also, non-zero bit offsets are unsupported and silently
replaced by zero. These issues are mostly independent from the
questions raised here, and work is under way to fix them.

3.2 DW_OP_piece on a Register
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

As opposed to DW_OP_bit_piece, the older DW_OP_piece operation
describes byte-aligned pieces only and does not allow specifying an
offset. Issues with this operation in GCC and GDB are mostly
restricted to "corner cases" like naturally left-aligned registers on
big-endian platforms.

3.2.1 DWARF Definition of DW_OP_piece
-------------------------------------

The standard says: "If the piece is located in a register, but does
not occupy the entire register, the placement of the piece within that
register is defined by the ABI."

This seems to imply the following:
1. The placement rule of DW_OP_piece is not necessarily related to the
placement rule of DW_OP_bit_piece. In particular, it would be
invalid to assume that DW_OP_piece is equivalent to DW_OP_bit_piece
with offset 0. (But note that this is exactly what GCC and GDB
currently assume.)
2. The placement can depend on the register as well as on size of the
piece. For instance, DW_OP_piece could be defined in accordance
with the SPU preferred slot.

* 3.2.1.1 What exactly may be defined by the ABI?

The standard is not explicit about the flexibility granted to the
ABI-specifics here. In particular:
- Do the pieces have to be contiguous?
- Assuming that the placement can depend on the size, must a piece at
least include all smaller pieces?
- Does a single-byte piece have to be at either end of the register?

3.2.2 Current GCC Usage of DW_OP_piece
--------------------------------------

GCC emits DW_OP_piece for a value that spans more than one register,
or for a virtual concatenation such as a complex value, etc.

One example is a `long double' value on z that has been scheduled into
a floating-point register pair. GCC represents this as a composition
of two DW_OP_piece operations of size 8, each referring to the *left*
end of the respective vector register.

GCC also emits DW_OP_piece for a register when an SRA-optimized field
with a multiple-of-8 bit size has been scheduled into it. This seems
to be under the assumption that DW_OP_piece is equivalent to
DW_OP_bit_piece with offset 0. One case where this is wrong is for an
`__int128' bit field residing in a vector register on z. Then the
DW_OP_piece emitted by GCC refers to the *right* end of the vector
register.

Another case where this would be wrong is when, say, a 56-bit
SRA-optimized bit field had been spilled into a floating-point
register. Then the actual bits reside at a non-zero offset from
*either* end of the vector register.

3.2.3 Current GDB Handling of DW_OP_piece
-----------------------------------------

GDB internally translates DW_OP_piece into DW_OP_bit_piece with offset
0 and the appropriate bit size. Then it takes the bitwise piece from
the left end on little-endian targets and from the right on big-endian
targets. Otherwise no ABI-specific logic is applied.

This is wrong for the floating-point-registers on z. For instance,
when a `complex float' value is pieced together from two
floating-point registers, the pieces ought to be taken from the left
end, but GDB takes them from the right end, typically yielding zero.

4 Options
=========

There are several different ways of fixing the issues described above.
However, the choice depends on how the DWARF standard is interpreted.
Here are some suggestions.

4.1 Literal Interpretation
~~~~~~~~~~~~~~~~~~~~~~~~~~

DW_OP_bit_piece: Start from the least significant bit of the first/last
register's byte on little-/big-endian targets,
respectively.
DW_OP_piece: Apply an ABI-specific placement rule which may depend on
the register and the piece length.

Also, whenever possible, define the ABI-specific placement rule for
DW_OP_piece such that DW_OP_regx is equivalent to DW_OP_regx followed
by `DW_OP_piece(len)', where `len' is the size of the object's data
type. In the case of z this means to take pieces from the left end
for FPRs/vector registers, and from the right end for general
(integer) registers. And for SPU registers it means to arrange the
pieces according to the "preferred slots".

But DW_OP_bit_piece, on the other hand, then uses offsets >= 64 to
designate any piece of an FPR on z. This is true even on older
systems without vector registers, because the DWARF register numbers
are the same -- offset zero is invalid there!

4.1.1 Discussion
----------------

Pros:
- This interpretation seems as close as possible to the current
standard's wording.
- DW_OP_piece can be used for cases like the SPU preferred slots.

Cons:
- The fact that FPRs on z start with a non-zero offset is rather odd
and could even be considered a violation of the standard. An
alternative might be to change the DWARF output of future compilers,
such as to assign new DWARF register numbers to vector registers.
However, that would render existing compilers' DWARF locations
invalid when vector registers are involved.
- Registers can not grow at the end of their "least significant bit".
The growth from 64-bit FPRs to 128-bit vector registers on z can be
accommodated with some drawbacks as explained above, but in the
future such cases would likely be handled by adding new DWARF
register numbers.

Resulting To-Dos:
- In the DWARF standard, clear up the meaning of the least significant
bit and highlight the difference between the placement rules of
DW_OP_piece and DW_OP_bit_piece. Add that DW_OP_piece shall be
equivalent to *some* DW_OP_bit_piece operation, but not necessarily
with offset 0.
- In GCC, drop the translation from DW_OP_bit_piece to DW_OP_piece, or
do it more carefully and involve ABI-specific logic.
- Enable GCC to emit DW_OP_bit_piece with a non-zero offset, for
instance in cases where an SRA-optimized bit field has been spilled
into an FPR on z.
- Equip GDB with ABI-specific logic for translating DW_OP_piece to the
appropriate bit piece.

4.2 Loose Interpretation
~~~~~~~~~~~~~~~~~~~~~~~~

DW_OP_bit_piece: Allow the ABI to define a per-register bit numbering
scheme.
DW_OP_piece: Apply an ABI-specific placement rule.

This is similar to the previous option but may avoid the issue with
invalid offset 0 within FPRs on z, e.g., by starting from the
register's *first* byte in this case.

Bit numbering schemes for DW_OP_bit_piece may be:

Architecture Alignment Bit order
-------------------------------------
little-endian left LSB0
little-endian right MSB0
big-endian right LSB0
big-endian left MSB0

For instance, the right-aligned little-endian scheme starts with the
most significant bit of the register's last byte. The FPRs and vector
registers on z might use the left-aligned big-endian scheme, which
starts with the most significant bit of the first byte.

4.2.1 Discussion
----------------

Pros:
- Each register can grow in an ABI-defined direction. This also
avoids the issue with non-zero offsets for FPRs on z.
- As with the "literal interpretation", DW_OP_piece can be used for
the SPU preferred slots.

Cons:
- Not quite in line with the current standard's wording, unless
assuming a fairly loose interpretation of "least significant bit".
- Requires two different ABI-specific mappings for DWARF pieces
instead of just one. This affects DWARF producers and consumers
alike.

Resulting To-Dos:
- Replace the DWARF standard's wording around the "least significant
bit". Enumerate the supported bit numbering schemes instead, and
state that the ABI shall assign one of them to each register.
Highlight the difference to DW_OP_piece.
- Fix GCC's translation from DW_OP_bit_piece to DW_OP_piece.
- In GCC, add an ABI-specific mapping from SRA-optimized bit fields to
DWARF bit pieces.
- Equip GDB with ABI-specific logic for translating DW_OP_piece to the
appropriate bit piece, as well as for assigning a bit numbering
scheme to each register.

4.3 Same Scheme for Bit- and Byte Pieces
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

DW_OP_bit_piece: Allow the ABI to define a per-register bit numbering
scheme.
DW_OP_piece: Same as the appropriately sized DW_OP_bit_piece at offset
0.

This definition is similar to the loose interpretation, but maintains
the assumption built into GCC, GDB, LLVM, and possibly other
DWARF-aware programs, that DW_OP_piece is just a short-hand notation
for DW_OP_bit_piece with offset 0.

However, this definition does not support the use of DW_OP_piece for
designating the SPU preferred slots. DW_OP_bit_piece must then be
used instead.

4.3.1 Discussion
----------------

Pros:
- Each register can grow in an ABI-defined direction.
- Maintains the assumption built into (all?) DWARF-aware software,
that DW_OP_piece translates to a DW_OP_bit_piece with offset 0.

Cons:
- Does not comply with the current standard's wording.
- DW_OP_piece can not be used for the SPU preferred slots.

Resulting To-Dos:
- Replace the DWARF standard's wording around the "least significant
bit" by an enumeration of supported bit numbering schemes and the
statement that the ABI shall assign one of them to each register.
Also define DW_OP_piece as DW_OP_bit_piece with offset 0.
- In GCC, add an ABI-specific mapping from SRA-optimized bit fields to
DWARF bit pieces.

5 Padding
=========

A related question is how to deal with a DWARF piece operation that
reaches fully or partially outside its underlying object. This is
currently not specified by the DWARF standard. It should probably be
stated that such a DWARF expression is invalid because pieces must be
fully contained in their underlying objects. Or otherwise it should
be explained where the extra bits are inserted, and how their values
are defined.

5.1 Stack Values
~~~~~~~~~~~~~~~~

For example, consider the following location description:

,----
| DW_OP_lit0 DW_OP_stack_value DW_OP_piece 936
`----

It *could* be argued that this is an efficient way of describing the
value of a 936-byte structure containing all zeroes.

Then, consequently, in this example...

,----
| DW_OP_const1s -1 DW_OP_stack_value DW_OP_piece 80
`----

...sign extension would be performed.

One reason to support the validity of such location descriptions is
that operations like DW_OP_lit<n> do not specify an object size, but
their resulting value could be viewed as having *infinite* size
instead. Of course, a different point of view is that the literal is
sign-extended to the special DWARF5 address type, thereby defining the
object size.

The examples above have an obvious natural alignment: The padding is
inserted beyond the end of the most significant bit, such that pieces
are right-aligned on big-endian targets and left-aligned on
little-endian targets. It is less obvious how this concept extends to
non-integer stack values.

5.2 Registers
~~~~~~~~~~~~~

For a location description like this there may or may not be a natural
alignment and padding:

,----
| DW_OP_reg5 DW_OP_bit_piece 1000 23
`----

To define the alignment, one option may be to follow the bit numbering
scheme used for DW_OP_bit_piece on that particular register. Padding
bits would then be inserted beyond the highest-numbered bit.

The value of the padding bits should probably always be set to zero,
because it is generally unknown whether the register currently holds a
signed or unsigned value.

5.3 Padding: Options
~~~~~~~~~~~~~~~~~~~~

Depending on the DWARF standard interpretation, one of the following
options could be pursued.

5.3.1 No padding support
------------------------

With this option, the DWARF standard might leave this area
unspecified, or perhaps explicitly state that pieces shall be fully
contained in their underlying objects.

DWARF consumers should then emit errors upon encountering invalid
pieces. GDB, for instance, does not currently emit such errors.

5.3.2 Padding support for integer stack values
----------------------------------------------

With this option, pieces must still be contained in their underlying
objects, except for integer stack values. Those are appropriately
sign-extended. In particular, this might be an efficient way of
describing large areas initialized with zero.

5.3.3 Padding support for stack values and registers
----------------------------------------------------

With this option, pieces reaching outside their underlying objects
would generally be padded, for stack values as well as for registers.

Padding and alignment for non-integer stack values and for registers
would have to be defined. It seems that, unless a very simple (yet
meaningful) scheme is found, it is probably not worth pursuing this.

6 Summary of Open Questions
===========================

1. Out of the standard interpretations discussed under "options"
(section 4) above, which do we want to settle on? Or is the
"preferred" interpretation missing from that list?
2. Should pieces fully or partially outside their underlying objects
be considered valid or invalid? If valid, how should they be
aligned and padded? In any case, what is the suggested treatment
by a DWARF consumer?