[Dwarf-Discuss] Corner-cases with bitfields

Lancelot SIX lsix.dwarf at lancelotsix.com
Fri May 6 10:11:53 PDT 2022


Dear all,

During our work on debugging support of compute workloads on AMDGPU[1],
we (at AMD) have been seeing two cases regarding description of
bitfields in DWARF for which we do not find definitive answers in the
DWARF documentation.  For those cases, when experiencing with usual CPU
targets we observe different behaviors on different toolchains.  As a
consequence, we would like to discuss those points here to gather
feedbacks.  If deemed necessary, we will submit a formal clarification
issue to the dwarf committee.

Both of the cases we present below impact how arguments are passed
during function calls in the ABI for at least our target (AMDGPU).
However, the debug information available to the debugger does not give
enough information to decide how to handle the type and the spec does
not really say what debug information should be generated to properly
describe those cases.  Also note that in both case, the DWARF
information we have is sufficient to describe the memory layout of the
types.

1 - Bitfield member with a size matching its underlying type:

The first point we would like to discuss is the one of  bitfield members
whose sizes match their underlying type.  Let's consider the following
example:

     struct Foo
     {
       char a : 8;
       char b : 8;
     };

If we compile such example with GCC it will add the `DW_AT_bit_size` and
`DW_AT_bit_offset` attributes to the `a` and `b` DIEs.

Clang on the other hand will not produce those attributes.

On the debugger side, GDB currently considers a struct member as being
packed (i.e. part of a bitfield) if it has the `DW_AT_bit_size`
attribute present and is non-0.  Therefore, GDB will "understand"
what GCC produces, but not what Clang produces.

What Clang does seems to be a reasonable thing to do if one is only
interested in the memory layout of the type.  This however is not
sufficient in our case to decide how to handle such type when
placing/inspecting arguments in registers in the context of function
calls. In our ABI, bitfield members are passed packed together, while
two chars in a struct would be placed in separate registers.

To clarify this situation, it would be helpful that a producer always
includes the DW_AT_bit_size attribute for bit field, which the standard
does not suggest nor require.

2 - Unnamed zero sized bitfield

Another case we met is related to unnamed fields with a size of 0 bits.
Such field is defined in the c++ standard as (in 9.6 Bit-Fields):

 > As a special case, an unnamed bit-field with a width of zero
 > specifies alignment of the next bit-field at an allocation unit
 > boundary

If we now consider an extended version of our previous example:

     struct Foo
     {
       char a : 8;
       char : 0;
       char b : 8,
     };

Neither GCC nor Clang give any information about the unnamed bitfield.
As for the previous case, the presence of such field impacts how
arguments are passed during function calls on our target, leaving the
debugger unable to properly decide how to handle such cases.

As for the previous case, both compilers can properly describe Foo's
memory layout using DW_AT_bit_offset.

It seems that such 0-sized field also has impact on ABI on other targets
such as armv7hl and aarch64 as discussed in [2].  Should the DWARF
specification give some guidance on how to handle such situation?

All thoughts on those cases are welcome.

Best,
Lancelot SIX.

[1] https://llvm.org/docs/AMDGPUUsage.html
[2] https://www.mail-archive.com/gcc@gcc.gnu.org/msg97797.html



More information about the Dwarf-Discuss mailing list