[Dwarf-Discuss] About self-referencial sized types

Pierre-Marie de Rodat derodat at adacore.com
Wed Apr 23 06:27:52 PDT 2014


I'm working on improvements for the DWARF information produced by GCC 
for Ada, and I have hit the following issue:

In Ada, it is possible to define array types inside structures (that are 
called records). The size of such array types can then depend on members 
of such records. For instance:

    type Array_Type is array (Integer range <>) of Integer;
    type Record_Type (N : Integer) is record
       A : Array_Type (1 .. N);
    end record;

Here, A's type is a "subtype" of Array_Type. It is an array whose upper 
bound is the special record member "N". I'm wondering how such bounds 
should be translated into DW_AT_{lower,upper}_bound attributes. The 
DWARFv4 specification (Appendix D, subsection 2.2 Ada Example) suggests 
the following DIEs (I'm stripping a few attributes that are not relevant 
for this issue):

  1$: DW_TAG_structure_type

  2$:   DW_TAG_member
            DW_AT_type(reference to Integer)

  3$:   DW_TAG_array_type
            DW_AT_type(reference to Integer)

  4$:     DW_TAG_subrange_type
              DW_AT_type(reference to Integer)
              DW_AT_lower_bound(constant 1)
              DW_AT_upper_bound(reference to member N at 2$)

  5$:   DW_TAG_member
            DW_AT_type(reference to array type at 4$)

With this debug info, the upper bound of "A" indeed completely mirrors 
the value of "N". In GCC, however, computing the upper bound of "A" is 
more subtle: it is internally represented as: max(0, <record>.N) so that 
when "N" is negative, 0 is returned.

While it is straightforward to reference a DIE from the 
DW_AT_upper_bound attribute, I struggle doing so inside a DWARF 
expression, and I do need a DWARF expression to correctly describe the 
computation of the upper bound. I guess I need an operation sequence 
that looks like:

    # Push N, then 0
    ??? Get the value of the "N" member;

    # Is N > 0?
    DW_OP_over; DW_OP_over;
    DW_OP_bra: 1;

    # If not then return 0, else return N.

So the issue for me is to know what to put instead of the "???" part. It 
looks like the DW_OP_push_object_address (defined in section 
Stack Operations) was introduced specifically for this kind of 
computation, but I'm not sure what it is supposed to mean in this 
context. Indeed, this operation would appear as part of a DWARF 
expression under a DW_TAG_subrange_type DIE, itself under a 
DW_TAG_array_type DIE, itself under a DW_TAG_structure_type. So what 
address would this operation push on top of the stack? The address of 
the "A" member, or the address of the embedding record?

The offsets of discriminants (the special record members that can be 
used to determine the size of regular record members) inside the record 
are statically known, so getting the address of the embedding record 
would be enough to be able to fetch the value of the discriminant. On 
the other hand, getting the address of the "A" member would not be 
sufficient: in more complex cases, the offset of the "A" member can 
depend on discriminants!

I tried to look at the implementation of DW_OP_push_object_address in 
GDB, but it looks like it's not implemented yet. What do you think about 
its expected behavior? And if I cannot use this operation for such array 
bound expressions, what should I use?

Thank you in advance for your answers. :-)

Pierre-Marie de Rodat

More information about the Dwarf-Discuss mailing list