Issue 240507.1: Add support for "properties"

Author: Martin Friebe
Champion: Adrian Prantl
Date submitted: 2024-05-07
Date revised: 2025-04-16
Date closed: 2025-03-31
Type: Enhancement
Status: Accepted
DWARF version: 6

Background

Pascal has a property construct, that allows a "variable like" identifier, which can either point to a field (member variable) or a getter/setter function.

TFoo = class
  FField: integer;
  function GetProp: integer;
  procedure SetProp(AVal: Integer);
  property MyProp: integer read GetProp write SetProp;
  property MyOtherProp: integer read FField;
end;

There may be partial overlaps with properties in Objective-C and C#.

Update: This proposal has been updated in a way to make to also useful for properties in Objective-C and Swift.

References

Proposed Changes

Section 2.1: The Debugging Information Entry

In Table 2.1, add DW_TAG_property, DW_TAG_property_getter, DW_TAG_property_setter, and DW_TAG_property_stored.

New Section 5.7.11 Property Entries

A property member is represented by a debugging information entry with the tag DW_TAG_property as specified in Section 5.19.

New Section 5.19(?): Property Entries

Add the following new subsection to Chapter 5:

5.19(?) Property Entries

[Non-normative] Object-oriented languages like Pascal and Objective-C have properties, which are variable- or data member-like entities of units or classes. Syntactically, properties can be accessed like variables and data members, however, access is implemented by invoking user-defined or compiler-generated subprograms, allowing programmed constraints, including read-only and write-only semantics.

A property is represented by a debugging information entry with the tag DW_TAG_property. A property entry has a DW_AT_name attribute, whose value is a null-terminated string containing the property name. A property entry has a DW_AT_type attribute to denote the type of that property.

A property may have DW_AT_external, DW_AT_virtuality, DW_AT_start_scope, DW_AT_decl_column, DW_AT_decl_file and DW_AT_decl_line attributes with the respective semantics described for these attributes for DW_TAG_member (see Section 5.7.6).

A property may have one or several of DW_TAG_property_getter, DW_TAG_property_setter, or DW_TAG_property_stored children to represent the getter and setter (member) functions, or underlying storage. A DW_TAG_property_stored child describes the Pascal-style stored accessor for a property. Each of these tags have a DW_AT_property_forward attribute to point to a (member) function declaration or a data member. If they point to a function, they may also have DW_TAG_formal_parameter children (matching the ones in the function) that can have DW_AT_default_value attributes to declare additional default arguments for when these functions are used as property accessors.

Some languages can automatically derive property accessors from a data member in property's parent entity. In such cases the DW_AT_property_forward attribute of the accessor entry points to the DW_TAG_property's sibling DW_TAG_member entry that holds the properties underlying storage. In the case of a global property it may point to a DW_TAG_variable or DW_TAG_constant.

Property accessors may also have any other attributes allowed in a DW_TAG_subprogram subroutine entry. If the value of a property can be derived by evaluating a DWARF expression, the DW_TAG_property_getter may have a DW_AT_location holding a DWARF expression that may use DW_OP_push_object_address to inquire the address of the property's parent entity.

To change the accessibility of a property in an inherited class, an access declaration [link to 5.7.4: Access Declarations] can be specified with the property name and accessibility. For example if an inherited property (InheritedProperty) becomes private in a subclass (SubClass), it is sufficient to add the following to the subclass entry:

DW_TAG_class
  DW_AT_name            "SubClass"
  DW_TAG_inheritance
    ...

  DW_TAG_access_declaration
    DW_AT_name            "InheritedProperty"
    DW_AT_accessibility   DW_ACCESS_private

Section 7

Add to Table 7.3

DW_TAG_property         0x4c
DW_TAG_property_getter  0x4d
DW_TAG_property_setter  0x4e
DW_TAG_property_stored  0x4f

Add to Table 7.5

DW_AT_property_forward  0x61  reference

Add to 7.32

Change bullet point 5 to:

If the tag in Step 3 is one of DW_TAG_pointer_type, DW_TAG_reference_type, DW_TAG_rvalue_reference_type, DW_TAG_ptr_to_member_type, DW_TAG_property_getter, DW_TAG_property_setter, DW_TAG_property_stored, or DW_TAG_friend, and the referenced type (via the DW_AT_type, DW_AT_property_forward, or DW_AT_friend attribute) has a DW_AT_name attribute, append to S the letter ’N’, the DWARF attribute code (DW_AT_type or DW_AT_friend), the context of the type (according to the method in Step 2), the letter ’E’, and the name of the type. For DW_AT_propery_forward and DW_AT_friend, if the referenced entry is a DW_TAG_subprogram, the context is omitted and the name to be used is the ABI-specific name of the subprogram (for example, the mangled linker name).

Appendix A:

Add to Table A.1:

TAG name Applicable attributes
DW_TAG_property DECL, DW_AT_type, DW_AT_external, DW_AT_virtuality, DW_AT_start_scope
DW_TAG_property_getter DECL, DW_AT_property_forward
DW_TAG_property_setter DECL, DW_AT_property_forward
DW_TAG_property_stored DECL, DW_AT_property_forward

Appendix D: Examples

Add a new subsection:

D.x Properties

The properties in the Pascal object in this example are represented by the following DWARF.

TClass = class
  private
     PrivateField: integer;
     function shouldStore : boolean;
  public
     function GetProp: integer;
     procedure SetProp(AVal: Integer);
     property PropFromMethods: integer read GetProp write SetProp;
     property PropFromField: integer read PrivateField;
     function GetValue(x: word; AIndex: Integer): char;
     property Indexed[x: word]: char index 1 read GetValue;
     property MaybeStored: integer stored shouldStore;
end;


DW_TAG_class_type
  DW_AT_name "TClass"
  DW_TAG_member
    DW_AT_accessibility DW_AT_private
    DW_AT_name "PrivateField"
    DW_AT_type <ref to integer>
  DW_TAG_subprogram
    DW_AT_name "GetProp"
    ...
  DW_TAG_subprogram
    DW_AT_name "SetProp"
    ...

  DW_TAG_property
    DW_AT_name "PropFromMethods"
    DW_TAG_property_getter
      DW_AT_property_forward <ref to GetProp>
    DW_TAG_property_setter
      DW_AT_property_forward <ref to SetProp>

  DW_TAG_property
    DW_AT_name "PropFromField"
    DW_TAG_property_getter
      DW_AT_property_forward <ref to PrivateField>

  DW_TAG_subprogram
    DW_AT_name "GetValue"
    ...

  DW_TAG_property
    DW_AT_name "Indexed"

    DW_TAG_property_getter
      DW_AT_property_forward <ref to GetValue>

      DW_TAG_formal_parameter  ; _this (no default specified, details inherited from GetValue
      DW_TAG_formal_parameter  ; x (no default specified)
      DW_TAG_formal_parameter
        DW_AT_default_value <DW_OP_lit 1> ; property index

  DW_TAG_property
    DW_AT_name "MaybeStored"

    DW_TAG_property_stored
      DW_AT_property_forward <ref to shouldStore>

2024-05-07: Original proposal.

2024-10-12: Revised after online discussion.

2025-01-03: Revised with updated examples and Chapter 7 changes.

2025-02-17: Revised with updated examples and Chapter 7 changes, and a fix to accessibility.

2025-03-03: Discussed in meeting. Change "field" (Pascal term) to "data member" (DWARF term); add updates for App. A; update Table 7.32 for type signature computation.

2025-03-10: Revised. Removed Pascal-specific wording from text in 5.19 (field -> data member); added updates for Appendix A; updated Section 7.32 for type signature computation.

2025-03-14: Revised. Adopted Ron's suggested wording for non-normative text in 5.19; changed name of inherited property.

2025-03-17: Tentatively accepted pending feedback from submitter.

2025-03-31: No feedback received. Accepted.

2025-04-16: Editorial change. Replaced "A property entry may have a DW_AT_name attribute..." with "A property entry has a DW_AT_name attribute...".