[Dwarf-Discuss] About self-referencial sized types

Todd Allen todd.allen at ccur.com
Tue May 27 09:16:15 PDT 2014


Pierre-Marie,

Sorry for the last response on this.  But perhaps an example from our Ada
compiler will help you.  This is slightly simplified (to get to the core of the
matter) DWARF dump for:

   type Record_Type2 (N : Integer) is 
      record
         A1 : Array_Type (1 .. N);
         A2 : Array_Type (1 .. N);
      end record;

This is what we produce for it, with some annotations from me:

DIE (0x9) [A$dw_record_type2.it]
        DW_TAG_structure_type
        DW_CHILDREN_yes
        DW_AT_name(DW_FORM_string) "record_type2"
   # The next DIE describes the actual "n" member visible to the user.
   DIE (0xa) [A$dw_n.D.record_type2.it]
           DW_TAG_member
           DW_CHILDREN_no
           DW_AT_type(DW_FORM_ref_addr) [A$dw_integer]
           DW_AT_data_member_location(DW_FORM_block) [DW_OP_plus_uconst 0]
           DW_AT_discriminant(DW_FORM_flag) TRUE
           DW_AT_name(DW_FORM_string) "n"
   # The next DIE describes a1'last.  It is artificial and anonymous, but has a
   # description which is "n", because that was the expression.
   DIE (0xf)
           DW_TAG_member
           DW_CHILDREN_no
           DW_AT_type(DW_FORM_ref_addr) 0xe (14) [A$dw_integer]
           DW_AT_artificial(DW_FORM_flag) TRUE
           DW_AT_data_member_location(DW_FORM_block) [DW_OP_plus_uconst 32]
           DW_AT_ccur_description(DW_FORM_string) "n"
   DIE (0xc) [A$dw_TYPE__BM2.record_type2.it..dmnd__B.it]
           DW_TAG_array_type
           DW_CHILDREN_yes
           DW_AT_subtype_parent(DW_FORM_ref_addr) [A$dw_array_type.it]
      DIE (0xd)
              DW_TAG_subrange_type
              DW_CHILDREN_no
              DW_AT_type(DW_FORM_ref_addr) [A$dw_integer]
              DW_AT_lower_bound(DW_FORM_sdata) 1
              DW_AT_upper_bound(DW_FORM_ref_addr) 0xf (15) []
   DIE (0x11) [A$dw_a1.record_type2.it]
           DW_TAG_member
           DW_CHILDREN_no
           DW_AT_type(DW_FORM_ref_addr) 0xc (12) [A$dw_TYPE__BM2.record_type2.it..dmnd__B.it]
           DW_AT_data_member_location(DW_FORM_block) [DW_OP_plus_uconst 8, DW_OP_dup, DW_OP_deref, DW_OP_plus]
           DW_AT_name(DW_FORM_string) "a1"
   # The next DIE describes a2'last.  It is artificial and anonymous, but has a
   # description which is "n", because that was the expression.
   DIE (0x18)
           DW_TAG_member
           DW_CHILDREN_no
           DW_AT_type(DW_FORM_ref_addr) 0x17 (23) [A$dw_integer]
           DW_AT_artificial(DW_FORM_flag) TRUE
           DW_AT_data_member_location(DW_FORM_block) [DW_OP_plus_uconst 72]
           DW_AT_ccur_description(DW_FORM_string) "n"
   DIE (0x15) [A$dw_TYPE__BM3.record_type2.it..dmnd__B.it]
           DW_TAG_array_type
           DW_CHILDREN_yes
           DW_AT_subtype_parent(DW_FORM_ref_addr) [A$dw_array_type.it]
      DIE (0x16)
              DW_TAG_subrange_type
              DW_CHILDREN_no
              DW_AT_type(DW_FORM_ref_addr) [A$dw_integer]
              DW_AT_lower_bound(DW_FORM_sdata) 1
              DW_AT_upper_bound(DW_FORM_ref_addr) 0x18 (24) []
   DIE (0x1a) [A$dw_a2.record_type2.it]
           DW_TAG_member
           DW_CHILDREN_no
           DW_AT_type(DW_FORM_ref_addr) 0x15 (21) [A$dw_TYPE__BM3.record_type2.it..dmnd__B.it]
           DW_AT_data_member_location(DW_FORM_block) [DW_OP_plus_uconst 48, DW_OP_dup, DW_OP_deref, DW_OP_plus]
           DW_AT_name(DW_FORM_string) "a2"

We're still emitting DW_AT_ccur_description, which was own of our own inventions
to support Ada.  But DWARF 3 adopted the canonical DW_AT_description which means
the same thing.

Anyway, the significant thing is that we're not referencing "n" directly, but
rather the stored values for the upper bound.  If you store the result of
max(0,n) somewhere, you could reference it directly.  For the case of general
expression upper bounds, you'd have to store the values somewhere (freeze them)
in case they might produce different results on subsequent evaluations.  But I
don't know if the max(0,n) might be a special case where you don't do that.

On Wed, Apr 23, 2014 at 09:27:52AM -0400, Pierre-Marie de Rodat wrote:
> Hi,
> 
> 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
>           DW_AT_name("Record_Type")
> 
>   2$:   DW_TAG_member
>             DW_AT_name("N")
>             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_name("A")
>             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;
>     DW_OP_lit0;
> 
>     # Is N > 0?
>     DW_OP_over; DW_OP_over;
>     DW_OP_gt;
>     DW_OP_bra: 1;
> 
>     # If not then return 0, else return N.
>     DW_OP_swap
>     DW_OP_drop
> 
> 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 2.5.1.3 
> 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
> 
> _______________________________________________
> Dwarf-Discuss mailing list
> Dwarf-Discuss at lists.dwarfstd.org
> http://lists.dwarfstd.org/listinfo.cgi/dwarf-discuss-dwarfstd.org

-- 
Todd Allen
Concurrent Computer Corporation


More information about the Dwarf-Discuss mailing list