On Thu, Jul 17, 2025 at 6:53 PM David Faust <david.fa...@oracle.com> wrote:
>
>
>
> On 7/17/25 05:16, Richard Biener wrote:
> > On Tue, Jul 15, 2025 at 12:03 AM David Faust <david.fa...@oracle.com> wrote:
> >>
> >> The btf_decl_tag and btf_type_tag attributes provide a means to annotate
> >> declarations and types respectively with arbitrary user provided
> >> strings.  These strings are recorded in debug information for
> >> post-compilation uses, and despite the name they are meant to be
> >> recorded in DWARF as well as BTF.  New DWARF extensions
> >> DW_TAG_GNU_annotation and DW_AT_GNU_annotation are used to represent
> >> these user annotations in DWARF.
> >>
> >> This patch introduces the new DWARF extension DIE and attribute, and
> >> generates them as necessary to represent user annotations from
> >> btf_decl_tag and btf_type_tag.
> >>
> >> The format of the new DIE is as follows:
> >>
> >>     DW_TAG_GNU_annotation
> >>         DW_AT_name: "btf_decl_tag" or "btf_type_tag"
> >>         DW_AT_const_value: <arbitrary user-supplied string>
> >>         DW_AT_GNU_annotation: <reference to another TAG_GNU_annotation DIE>
> >>
> >> DW_AT_GNU_annotation is a new attribute extension used to refer to these
> >> new annotation DIEs.  If non-null in any given declaration or type DIE,
> >> it is a reference to a DW_TAG_GNU_annotation DIE holding an annotation
> >> for that declaration or type.  In addition, the DW_TAG_GNU_annotation
> >> DIEs may also have a non-null DW_AT_GNU_annotation, referring to another
> >> annotation DIE.  This allows chains of annotation DIEs to be formed,
> >> such as in the case where a single declaration has multiple instances of
> >> btf_decl_tag with different string annotations.
> >
> > Thanks - this looks a lot better, but see below.
>
> I am also happier with it thanks to your help :)
>
> >
> >> gcc/
> >>         * dwarf2out.cc (struct annotation_node, struct 
> >> annotation_node_hasher)
> >>         (btf_tag_htab): New ancillary structures and hash table.
> >>         (annotation_node_hasher::hash, annotation_node_hasher::equal): New.
> >>         (hash_btf_tag, gen_btf_tag_dies, gen_btf_type_tag_dies)
> >>         (maybe_gen_btf_type_tag_dies, maybe_gen_btf_decl_tag_dies): New 
> >> functions.
> >>         (modified_type_die): Add new argument to pass btf_type_tag 
> >> attribute.
> >>         Handle btf_type_tag, and update recursive calls.
> >>         (base_type_for_mode): Add new arg for modified_type_die call.
> >>         (add_type_attribute): Likewise.
> >>         (gen_array_type_die): Call maybe_gen_btf_type_tag_dies for the 
> >> type.
> >>         (gen_formal_parameter_die): Call maybe_gen_btf_decl_tag_dies for 
> >> the
> >>         parameter.
> >>         (override_type_for_decl_p): Add new arg for modified_type_die call.
> >>         (force_type_die): Likewise.
> >>         (gen_tagged_type_die): Call maybe_gen_btf_type_tag_dies for the 
> >> type.
> >>         (gen_decl_die): Call maybe_gen_btf_decl_tag_dies for the decl.
> >>         (dwarf2out_finish): Empty btf_tag_htab.
> >>         (dwarf2out_cc_finalize): Delete btf_tag_htab hash table.
> >>
> >> include/
> >>         * dwarf2.def (DW_TAG_GNU_annotation): New DWARF extension.
> >>         (DW_AT_GNU_annotation): Likewise.
> >>
> >> gcc/testsuite/
> >>         * gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-1.c: New test.
> >>         * gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-2.c: New test.
> >>         * gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-3.c: New test.
> >>         * gcc.dg/debug/dwarf2/dwarf-btf-type-tag-1.c: New test.
> >>         * gcc.dg/debug/dwarf2/dwarf-btf-type-tag-2.c: New test.
> >>         * gcc.dg/debug/dwarf2/dwarf-btf-type-tag-3.c: New test.
> >>         * gcc.dg/debug/dwarf2/dwarf-btf-type-tag-4.c: New test.
> >>         * gcc.dg/debug/dwarf2/dwarf-btf-type-tag-5.c: New test.
> >>         * gcc.dg/debug/dwarf2/dwarf-btf-type-tag-6.c: New test.
> >>         * gcc.dg/debug/dwarf2/dwarf-btf-type-tag-7.c: New test.
> >> ---
> >>  gcc/dwarf2out.cc                              | 337 ++++++++++++++++--
> >>  .../debug/dwarf2/dwarf-btf-decl-tag-1.c       |  11 +
> >>  .../debug/dwarf2/dwarf-btf-decl-tag-2.c       |  25 ++
> >>  .../debug/dwarf2/dwarf-btf-decl-tag-3.c       |  21 ++
> >>  .../debug/dwarf2/dwarf-btf-type-tag-1.c       |  10 +
> >>  .../debug/dwarf2/dwarf-btf-type-tag-2.c       |  31 ++
> >>  .../debug/dwarf2/dwarf-btf-type-tag-3.c       |  15 +
> >>  .../debug/dwarf2/dwarf-btf-type-tag-4.c       |  34 ++
> >>  .../debug/dwarf2/dwarf-btf-type-tag-5.c       |  10 +
> >>  .../debug/dwarf2/dwarf-btf-type-tag-6.c       |  27 ++
> >>  .../debug/dwarf2/dwarf-btf-type-tag-7.c       |  25 ++
> >>  include/dwarf2.def                            |   4 +
> >>  12 files changed, 527 insertions(+), 23 deletions(-)
> >>  create mode 100644 
> >> gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-1.c
> >>  create mode 100644 
> >> gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-2.c
> >>  create mode 100644 
> >> gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-3.c
> >>  create mode 100644 
> >> gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-type-tag-1.c
> >>  create mode 100644 
> >> gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-type-tag-2.c
> >>  create mode 100644 
> >> gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-type-tag-3.c
> >>  create mode 100644 
> >> gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-type-tag-4.c
> >>  create mode 100644 
> >> gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-type-tag-5.c
> >>  create mode 100644 
> >> gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-type-tag-6.c
> >>  create mode 100644 
> >> gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-type-tag-7.c
> >>
> >> diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc
> >> index d1a55dbcbcb..20007f439a2 100644
> >> --- a/gcc/dwarf2out.cc
> >> +++ b/gcc/dwarf2out.cc
> >> @@ -3696,6 +3696,33 @@ static bool frame_pointer_fb_offset_valid;
> >>
> >>  static vec<dw_die_ref> base_types;
> >>
> >> +/* A cached btf_type_tag or btf_decl_tag user annotation.  */
> >> +struct GTY ((for_user)) annotation_node
> >> +{
> >> +  const char *name;
> >> +  const char *value;
> >> +  hashval_t hash;
> >> +  dw_die_ref die;
> >> +  struct annotation_node *next;
> >> +};
> >> +
> >> +/* Hasher for btf_type_tag and btf_decl_tag annotation nodes.  */
> >> +struct annotation_node_hasher : ggc_ptr_hash<annotation_node>
> >> +{
> >> +  typedef const struct annotation_node *compare_type;
> >> +
> >> +  static hashval_t hash (struct annotation_node *);
> >> +  static bool equal (const struct annotation_node *,
> >> +                    const struct annotation_node *);
> >> +};
> >> +
> >> +/* A hash table of tag annotation nodes for btf_type_tag and btf_decl_tag 
> >> C
> >> +   attributes.  DIEs for these user annotations may be reused if they are
> >> +   structurally equivalent; this hash table is used to ensure the DIEs are
> >> +   reused wherever possible.  */
> >> +static GTY (()) hash_table<annotation_node_hasher> *btf_tag_htab;
> >> +
> >> +
> >>  /* Flags to represent a set of attribute classes for attributes that 
> >> represent
> >>     a scalar value (bounds, pointers, ...).  */
> >>  enum dw_scalar_form
> >> @@ -3840,7 +3867,7 @@ static void output_file_names (void);
> >>  static bool is_base_type (tree);
> >>  static dw_die_ref subrange_type_die (tree, tree, tree, tree, dw_die_ref);
> >>  static int decl_quals (const_tree);
> >> -static dw_die_ref modified_type_die (tree, int, bool, dw_die_ref);
> >> +static dw_die_ref modified_type_die (tree, int, bool, dw_die_ref, tree);
> >>  static dw_die_ref generic_parameter_die (tree, tree, bool, dw_die_ref);
> >>  static dw_die_ref template_parameter_pack_die (tree, tree, dw_die_ref);
> >>  static unsigned int debugger_reg_number (const_rtx);
> >> @@ -13659,6 +13686,206 @@ long_double_as_float128 (tree type)
> >>    return NULL_TREE;
> >>  }
> >>
> >> +/* Hash function for struct annotation_node.  The hash value is computed 
> >> when
> >> +   the annotation node is created based on the name, value and chain of 
> >> any
> >> +   further annotations on the same entity.  */
> >> +
> >> +hashval_t
> >> +annotation_node_hasher::hash (struct annotation_node *node)
> >> +{
> >> +  return node->hash;
> >> +}
> >> +
> >> +/* Return whether two annotation nodes represent the same annotation and
> >> +   can therefore share a DIE.  Beware of hash value collisions.  */
> >> +
> >> +bool
> >> +annotation_node_hasher::equal (const struct annotation_node *node1,
> >> +                              const struct annotation_node *node2)
> >> +{
> >> +  return (node1->hash == node2->hash
> >> +         && (node1->name == node2->name
> >> +             || !strcmp (node1->name, node2->name))
> >> +         && (node1->value == node2->value
> >> +             || !strcmp (node1->value, node2->value))
> >> +         && node1->next == node2->next);
> >> +}
> >> +
> >> +/* Return an appropriate entry in the btf tag hash table for a given btf 
> >> tag.
> >> +   If a structurally equivalent tag (one with the same name, value, and
> >> +   subsequent chain of further tags) has already been processed, then the
> >> +   existing entry for that tag is returned and should be reused.
> >> +   Otherwise, a new entry is added to the hash table and returned.  */
> >> +
> >> +static struct annotation_node *
> >> +hash_btf_tag (tree attr)
> >> +{
> >> +  if (attr == NULL_TREE || TREE_CODE (attr) != TREE_LIST)
> >> +    return NULL;
> >> +
> >> +  if (!btf_tag_htab)
> >> +    btf_tag_htab = hash_table<annotation_node_hasher>::create_ggc (10);
> >> +
> >> +  const char * name = IDENTIFIER_POINTER (get_attribute_name (attr));
> >> +  const char * value = TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE 
> >> (attr)));
> >> +  tree chain = lookup_attribute (name, TREE_CHAIN (attr));
> >> +
> >> +  /* Hash for one tag depends on hash of next tag in the chain, because
> >> +     the chain is part of structural equivalence.  */
> >> +  struct annotation_node *chain_node = hash_btf_tag (chain);
> >> +  gcc_checking_assert (chain == NULL_TREE || chain_node != NULL);
> >> +
> >> +  /* Skip any non-btf-tag attributes that might be in the chain.  */
> >> +  if (strcmp (name, "btf_type_tag") != 0 && strcmp (name, "btf_decl_tag") 
> >> != 0)
> >> +    return chain_node;
> >> +
> >> +  /* Hash for a given tag is determined by the name, value, and chain of
> >> +     further tags.  */
> >> +  inchash::hash h;
> >> +  h.merge_hash (htab_hash_string (name));
> >> +  h.merge_hash (htab_hash_string (value));
> >> +  h.merge_hash (chain_node ? chain_node->hash : 0);
> >> +
> >> +  struct annotation_node node;
> >> +  node.name = name;
> >> +  node.value = value;
> >> +  node.hash = h.end ();
> >> +  node.next = chain_node;
> >> +
> >> +  struct annotation_node **slot = btf_tag_htab->find_slot (&node, INSERT);
> >> +  if (*slot == NULL)
> >> +    {
> >> +      /* Create new htab entry for this annotation.  */
> >> +      struct annotation_node *new_slot
> >> +       = ggc_cleared_alloc<struct annotation_node> ();
> >> +      new_slot->name = name;
> >> +      new_slot->value = value;
> >> +      new_slot->hash = node.hash;
> >> +      new_slot->next = chain_node;
> >> +
> >> +      *slot = new_slot;
> >> +      return new_slot;
> >> +    }
> >> +  else
> >> +    {
> >> +      /* This node is already in the hash table.  */
> >> +      return *slot;
> >> +    }
> >> +}
> >> +
> >> +/* Generate (or reuse) DW_TAG_GNU_annotation DIEs representing the 
> >> btf_type_tag
> >> +   or btf_decl_tag user annotations in ATTR, and update DIE to refer to 
> >> them
> >> +   via DW_AT_GNU_annotation.  If there are multiple type_tag or decl_tag
> >> +   annotations in ATTR, they are all processed recursively by this 
> >> function to
> >> +   build a chain of annotation DIEs.
> >> +   A single chain of annotation DIEs can be shared among all occurrences 
> >> of
> >> +   equivalent sets of attributes appearing on different types or 
> >> declarations.
> >> +   Return the first annotation DIE in the created (or reused) chain.  */
> >> +
> >> +static dw_die_ref
> >> +gen_btf_tag_dies (tree attr, dw_die_ref die, dw_die_ref context_die)
> >> +{
> >> +  if (attr == NULL_TREE)
> >> +    return die;
> >> +
> >> +  while (dw_get_die_tag (context_die) != DW_TAG_compile_unit)
> >> +    context_die = context_die->die_parent;
> >
> > This should be always comp_unit_die ().  But, seeing this I wonder
> > how this interacts with -fdebug-types aka type units?  I would expect
> > us to duplicate the btf-tag DIEs into the type units, so it should work.
> > But can you double-check?
>
> Thanks, to be honest I did not consider -fdebug-types-section.
> Fortunately, looks like it does indeed "just work" and the btf-tag DIEs
> are duplicated into the type units as necessary.
>
> Regarding "should be always comp_unit_die ()": I thought so too, but I
> wasn't sure whether I forgot something (like -fdebug-types...)
>
> In that case I wonder whether we need to pass context_die at all here.
> From a quick check, just using comp_unit_die () gives the same output,
> also with -fdebug-types, and the intended design is that the tag dies
> are added as children of the top-level CU (or type unit) die.

Yes, no need to pass down the context if you want to have the tag lists
at CU level.

> >
> >> +
> >> +  const char * name = IDENTIFIER_POINTER (get_attribute_name (attr));
> >> +  const char * value = TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE 
> >> (attr)));
> >> +
> >> +  dw_die_ref tag_die, prev = NULL;
> >> +
> >> +  /* Multiple annotations on the same item form a singly-linked list of
> >> +     annotation DIEs; generate recursively backward from the end so we can
> >> +     chain each created DIE to the next, which has already been created.  
> >> */
> >> +  tree rest = lookup_attribute (name, TREE_CHAIN (attr));
> >> +  if (rest)
> >> +    prev = gen_btf_tag_dies (rest, NULL, context_die);
> >> +
> >> +  /* Calculate a hash value for the tag based on its structure, find the
> >> +     existing entry for it (if any) in the hash table, or create a new 
> >> entry
> >> +     which can be reused by structurally-equivalent tags.  */
> >> +  struct annotation_node *entry = hash_btf_tag (attr);
> >> +  if (!entry)
> >> +    return die;
> >> +
> >> +  /* If the node already has an associated DIE, reuse it.
> >> +     Otherwise, create the new annotation DIE, and associate it with
> >> +     the hash table entry for future reuse.  Any structurally-equivalent
> >> +     tag we process later will find and share the same DIE.  */
> >> +  if (entry->die)
> >> +    tag_die = entry->die;
> >> +  else
> >> +    {
> >> +      tag_die = new_die (DW_TAG_GNU_annotation, context_die, NULL);
> >> +      add_name_attribute (tag_die, name);
> >> +      add_AT_string (tag_die, DW_AT_const_value, value);
> >> +      if (prev)
> >> +       add_AT_die_ref (tag_die, DW_AT_GNU_annotation, prev);
> >> +
> >> +      entry->die = tag_die;
> >> +    }
> >> +
> >> +  if (die)
> >> +    {
> >> +      /* Add AT_GNU_annotation referring to the annotation DIE.
> >> +        It may have already been added, some global declarations are 
> >> processed
> >> +        twice, but if so it must be the same or we have a bug.  */
> >> +      dw_die_ref existing = get_AT_ref (die, DW_AT_GNU_annotation);
> >> +      if (existing)
> >> +       gcc_checking_assert (existing == tag_die);
> >> +      else
> >> +       add_AT_die_ref (die, DW_AT_GNU_annotation, tag_die);
> >> +    }
> >> +
> >> +  return tag_die;
> >> +}
> >> +
> >> +/* Generate (or reuse) annotation DIEs representing any type_tags in 
> >> ATTR, and
> >> +   update TARGET to refer to them via DW_AT_GNU_annotation.  */
> >> +
> >> +static void
> >> +gen_btf_type_tag_dies (tree tags, dw_die_ref target, dw_die_ref 
> >> context_die)
> >> +{
> >> +  if (!target)
> >> +    return;
> >> +
> >> +  gen_btf_tag_dies (tags, target, context_die);
> >> +}
> >> +
> >> +/* Generate (or reuse) annotation DIEs representing the type_tags on T, if
> >> +   any, and update DIE to refer to them as appropriate.  */
> >> +
> >> +static void
> >> +maybe_gen_btf_type_tag_dies (tree t, dw_die_ref target, dw_die_ref 
> >> context_die)
> >> +{
> >> +  if (t == NULL_TREE || !TYPE_P (t) || !target)
> >> +    return;
> >> +
> >> +  tree attr = lookup_attribute ("btf_type_tag", TYPE_ATTRIBUTES (t));
> >> +  if (attr == NULL_TREE)
> >> +    return;
> >> +
> >> +  gen_btf_type_tag_dies (attr, target, context_die);
> >> +}
> >> +
> >> +/* Generate (or reuse) annotation DIEs representing any decl_tags in ATTR 
> >> that
> >> +   apply to TARGET.  */
> >> +
> >> +static void
> >> +maybe_gen_btf_decl_tag_dies (tree t, dw_die_ref target, dw_die_ref 
> >> context_die)
> >> +{
> >> +  if (t == NULL_TREE || !DECL_P (t) || !target)
> >> +    return;
> >> +
> >> +  tree attr = lookup_attribute ("btf_decl_tag", DECL_ATTRIBUTES (t));
> >> +  if (attr == NULL_TREE)
> >> +    return;
> >> +
> >> +  gen_btf_tag_dies (attr, target, context_die);
> >> +}
> >> +
> >>  /* Given a pointer to an arbitrary ..._TYPE tree node, return a debugging
> >>     entry that chains the modifiers specified by CV_QUALS in front of the
> >>     given type.  REVERSE is true if the type is to be interpreted in the
> >> @@ -13666,7 +13893,7 @@ long_double_as_float128 (tree type)
> >>
> >>  static dw_die_ref
> >>  modified_type_die (tree type, int cv_quals, bool reverse,
> >> -                  dw_die_ref context_die)
> >> +                  dw_die_ref context_die, tree tag_attrs)
> >
> > The new param lacks documentation in the function-level comment.  I
> > see below that
> > you only ever pass "btf-tag" attributes here but I hoped this could be
> > the vehicle
> > to handle more attributes in the future.  So I wonder if you can instead 
> > make
> > the argument carry the full attribute list from TYPE_ATTRIBUTES?
>
> Thanks, will add the doc commment.
>
> Yes, passing the full TYPE_ATTRIBUTES makes sense and is straightforward
> from initial testing. It gives a nice parallel to cv-quals with many callers
> passing TYPE_QUALS and now TYPE_ATTRIBUTES. Nice :)
>
> In that case WDYT about inserting the new arg as type_attrs like so:
>
> modified_type_die (tree type, int cv_quals, tree type_attrs,
>                    bool reverse, dw_die_ref context_die)

Sure, that works for me.

> > I'm also not
> > sure whether your implementation handles the case of two attributes on the
> > same type (it might be your updated attribute handler forces multiple
> > type variants
> > then?).
>
> Yes, it still works with the change in the attribute handler.
>
> >
> > From a quick look there's no test coverage for
> >
> > typedef int myint __attribute__((btf_tag("A"),btf_tag("B")));
> >
> > and what's expected from that.
>
> Test dwarf2/btf-type-tag-2.c has a couple of multi-tag types,  but not in
> the same __attribute__ (()). I will add another test for this specifically,
> and also to stress more cases of having several tags on the same type.

Thanks!

Richard.

> Thank you,
> David
>
> >
> > Thanks,
> > Richard.
> >
> >>  {
> >>    enum tree_code code = TREE_CODE (type);
> >>    dw_die_ref mod_type_die;
> >> @@ -13693,7 +13920,8 @@ modified_type_die (tree type, int cv_quals, bool 
> >> reverse,
> >>        tree debug_type = lang_hooks.types.get_debug_type (type);
> >>
> >>        if (debug_type != NULL_TREE && debug_type != type)
> >> -       return modified_type_die (debug_type, cv_quals, reverse, 
> >> context_die);
> >> +       return modified_type_die (debug_type, cv_quals, reverse, 
> >> context_die,
> >> +                                 tag_attrs);
> >>      }
> >>
> >>    cv_quals &= cv_qual_mask;
> >> @@ -13771,7 +13999,7 @@ modified_type_die (tree type, int cv_quals, bool 
> >> reverse,
> >>              abstract origin instead.  */
> >>           if (origin != NULL && origin != name)
> >>             return modified_type_die (TREE_TYPE (origin), cv_quals, 
> >> reverse,
> >> -                                     context_die);
> >> +                                     context_die, tag_attrs);
> >>
> >>           /* For a named type, use the typedef.  */
> >>           gen_type_die (qualified_type, context_die);
> >> @@ -13783,10 +14011,35 @@ modified_type_die (tree type, int cv_quals, bool 
> >> reverse,
> >>           dquals &= cv_qual_mask;
> >>           if ((dquals & ~cv_quals) != TYPE_UNQUALIFIED
> >>               || (cv_quals == dquals && DECL_ORIGINAL_TYPE (name) != type))
> >> -           /* cv-unqualified version of named type.  Just use
> >> -              the unnamed type to which it refers.  */
> >> -           return modified_type_die (DECL_ORIGINAL_TYPE (name), cv_quals,
> >> -                                     reverse, context_die);
> >> +           {
> >> +             tree dtags = lookup_attribute ("btf_type_tag",
> >> +                                            TYPE_ATTRIBUTES (dtype));
> >> +             if (tag_attrs && !attribute_list_equal (tag_attrs, dtags))
> >> +               {
> >> +                 /* Use of a typedef with additional btf_type_tags.
> >> +                    Create a new typedef DIE to which we can attach the
> >> +                    additional type_tag DIEs without disturbing other 
> >> users of
> >> +                    the underlying typedef.  */
> >> +                 dw_die_ref mod_die
> >> +                   = modified_type_die (dtype, cv_quals, reverse, 
> >> context_die,
> >> +                                        NULL_TREE);
> >> +
> >> +                 mod_die = clone_die (mod_die);
> >> +                 add_child_die (comp_unit_die (), mod_die);
> >> +                 if (!lookup_type_die (type))
> >> +                   equate_type_number_to_die (type, mod_die);
> >> +
> >> +                 /* Now generate the type_tag DIEs only for the new
> >> +                    type_tags appearing in the use of the typedef, and
> >> +                    attach them to the cloned typedef DIE.  */
> >> +                 gen_btf_type_tag_dies (tag_attrs, mod_die, context_die);
> >> +                 return mod_die;
> >> +               }
> >> +             /* cv-unqualified version of named type.  Just use
> >> +                the unnamed type to which it refers.  */
> >> +             return modified_type_die (DECL_ORIGINAL_TYPE (name), 
> >> cv_quals,
> >> +                                       reverse, context_die, tag_attrs);
> >> +           }
> >>           /* Else cv-qualified version of named type; fall through.  */
> >>         }
> >>      }
> >> @@ -13820,7 +14073,8 @@ modified_type_die (tree type, int cv_quals, bool 
> >> reverse,
> >>                 break;
> >>               }
> >>         }
> >> -      mod_type_die = modified_type_die (type, sub_quals, reverse, 
> >> context_die);
> >> +      mod_type_die = modified_type_die (type, sub_quals, reverse,
> >> +                                       context_die, tag_attrs);
> >>        if (mod_scope && mod_type_die && mod_type_die->die_parent == 
> >> mod_scope)
> >>         {
> >>           /* As not all intermediate qualified DIEs have corresponding
> >> @@ -13887,6 +14141,15 @@ modified_type_die (tree type, int cv_quals, bool 
> >> reverse,
> >>             first_quals |= dwarf_qual_info[i].q;
> >>           }
> >>      }
> >> +  else if (tag_attrs)
> >> +    {
> >> +      /* First create a DIE for the type without any type_tag attribute.
> >> +        Then generate TAG_GNU_annotation DIEs for the type_tags.  */
> >> +      dw_die_ref mod_die = modified_type_die (type, cv_quals, reverse,
> >> +                                             context_die, NULL_TREE);
> >> +      gen_btf_type_tag_dies (tag_attrs, mod_die, context_die);
> >> +      return mod_die;
> >> +    }
> >>    else if (code == POINTER_TYPE || code == REFERENCE_TYPE)
> >>      {
> >>        dwarf_tag tag = DW_TAG_pointer_type;
> >> @@ -13951,9 +14214,13 @@ modified_type_die (tree type, int cv_quals, bool 
> >> reverse,
> >>         {
> >>           dw_die_ref other_die;
> >>           if (TYPE_NAME (other_type))
> >> -           other_die
> >> -             = modified_type_die (other_type, TYPE_UNQUALIFIED, reverse,
> >> -                                  context_die);
> >> +           {
> >> +             tree other_attr = lookup_attribute ("btf_type_tag",
> >> +                                                 TYPE_ATTRIBUTES 
> >> (other_type));
> >> +             other_die
> >> +               = modified_type_die (other_type, TYPE_UNQUALIFIED, reverse,
> >> +                                    context_die, other_attr);
> >> +           }
> >>           else
> >>             {
> >>               other_die = base_type_die (type, reverse);
> >> @@ -13972,7 +14239,7 @@ modified_type_die (tree type, int cv_quals, bool 
> >> reverse,
> >>        if (reverse_type)
> >>         {
> >>           dw_die_ref after_die
> >> -           = modified_type_die (type, cv_quals, false, context_die);
> >> +           = modified_type_die (type, cv_quals, false, context_die, 
> >> tag_attrs);
> >>           add_child_die_after (mod_scope, mod_type_die, after_die);
> >>         }
> >>        else
> >> @@ -13986,7 +14253,7 @@ modified_type_die (tree type, int cv_quals, bool 
> >> reverse,
> >>        if (reverse_type)
> >>         {
> >>           dw_die_ref after_die
> >> -           = modified_type_die (type, cv_quals, false, context_die);
> >> +           = modified_type_die (type, cv_quals, false, context_die, 
> >> tag_attrs);
> >>           gen_type_die (type, context_die, true);
> >>           gcc_assert (after_die->die_sib
> >>                       && get_AT_unsigned (after_die->die_sib, 
> >> DW_AT_endianity));
> >> @@ -14076,8 +14343,9 @@ modified_type_die (tree type, int cv_quals, bool 
> >> reverse,
> >>         types are possible in Ada.  */
> >>      sub_die = modified_type_die (item_type,
> >>                                  TYPE_QUALS_NO_ADDR_SPACE (item_type),
> >> -                                reverse,
> >> -                                context_die);
> >> +                                reverse, context_die,
> >> +                                lookup_attribute ("btf_type_tag",
> >> +                                                  TYPE_ATTRIBUTES 
> >> (item_type)));
> >>
> >>    if (sub_die != NULL)
> >>      add_AT_die_ref (mod_type_die, DW_AT_type, sub_die);
> >> @@ -15222,7 +15490,7 @@ base_type_for_mode (machine_mode mode, bool 
> >> unsignedp)
> >>    type_die = lookup_type_die (type);
> >>    if (!type_die)
> >>      type_die = modified_type_die (type, TYPE_UNQUALIFIED, false,
> >> -                                 comp_unit_die ());
> >> +                                 comp_unit_die (), NULL_TREE);
> >>    if (type_die == NULL || type_die->die_tag != DW_TAG_base_type)
> >>      return NULL;
> >>    return type_die;
> >> @@ -22493,7 +22761,9 @@ add_type_attribute (dw_die_ref object_die, tree 
> >> type, int cv_quals,
> >>    type_die = modified_type_die (type,
> >>                                 cv_quals | TYPE_QUALS (type),
> >>                                 reverse,
> >> -                               context_die);
> >> +                               context_die,
> >> +                               lookup_attribute ("btf_type_tag",
> >> +                                                 TYPE_ATTRIBUTES (type)));
> >>
> >>    if (type_die != NULL)
> >>      add_AT_die_ref (object_die, DW_AT_type, type_die);
> >> @@ -22770,6 +23040,7 @@ gen_array_type_die (tree type, dw_die_ref 
> >> context_die)
> >>      add_pubtype (type, array_die);
> >>
> >>    add_alignment_attribute (array_die, type);
> >> +  maybe_gen_btf_type_tag_dies (type, array_die, context_die);
> >>  }
> >>
> >>  /* This routine generates DIE for array with hidden descriptor, details
> >> @@ -23140,6 +23411,8 @@ gen_formal_parameter_die (tree node, tree origin, 
> >> bool emit_name_p,
> >>           else
> >>             {
> >>               add_child_die (context_die, parm_die);
> >> +             maybe_gen_btf_decl_tag_dies (node_or_origin, parm_die,
> >> +                                          context_die);
> >>               return parm_die;
> >>             }
> >>         }
> >> @@ -23208,6 +23481,8 @@ gen_formal_parameter_die (tree node, tree origin, 
> >> bool emit_name_p,
> >>        gcc_unreachable ();
> >>      }
> >>
> >> +  maybe_gen_btf_decl_tag_dies (node_or_origin, parm_die, context_die);
> >> +
> >>    return parm_die;
> >>  }
> >>
> >> @@ -24561,10 +24836,13 @@ override_type_for_decl_p (tree decl, dw_die_ref 
> >> old_die,
> >>    else
> >>      cv_quals = decl_quals (decl);
> >>
> >> -  dw_die_ref type_die = modified_type_die (type,
> >> -                                          cv_quals | TYPE_QUALS (type),
> >> -                                          false,
> >> -                                          context_die);
> >> +  dw_die_ref type_die
> >> +    = modified_type_die (type,
> >> +                        cv_quals | TYPE_QUALS (type),
> >> +                        false,
> >> +                        context_die,
> >> +                        lookup_attribute ("btf_type_tag",
> >> +                                          TYPE_ATTRIBUTES (type)));
> >>
> >>    dw_die_ref old_type_die = get_AT_ref (old_die, DW_AT_type);
> >>
> >> @@ -26432,6 +26710,10 @@ gen_tagged_type_die (tree type,
> >>    else
> >>      gen_struct_or_union_type_die (type, context_die, usage);
> >>
> >> +  dw_die_ref die = lookup_type_die (type);
> >> +  if (die)
> >> +    maybe_gen_btf_type_tag_dies (type, die, context_die);
> >> +
> >>    /* Don't set TREE_ASM_WRITTEN on an incomplete struct; we want to fix
> >>       it up if it is ever completed.  gen_*_type_die will set it for us
> >>       when appropriate.  */
> >> @@ -27065,7 +27347,9 @@ force_type_die (tree type)
> >>        dw_die_ref context_die = get_context_die (TYPE_CONTEXT (type));
> >>
> >>        type_die = modified_type_die (type, TYPE_QUALS_NO_ADDR_SPACE (type),
> >> -                                   false, context_die);
> >> +                                   false, context_die,
> >> +                                   lookup_attribute ("btf_type_tag",
> >> +                                                     TYPE_ATTRIBUTES 
> >> (type)));
> >>        gcc_assert (type_die);
> >>      }
> >>    return type_die;
> >> @@ -27442,6 +27726,9 @@ gen_decl_die (tree decl, tree origin, struct 
> >> vlr_context *ctx,
> >>        break;
> >>      }
> >>
> >> +  maybe_gen_btf_decl_tag_dies (decl_or_origin, lookup_decl_die 
> >> (decl_or_origin),
> >> +                              context_die);
> >> +
> >>    return NULL;
> >>  }
> >>
> >> @@ -32488,6 +32775,9 @@ dwarf2out_finish (const char *filename)
> >>    /* Flush out any latecomers to the limbo party.  */
> >>    flush_limbo_die_list ();
> >>
> >> +  if (btf_tag_htab)
> >> +    btf_tag_htab->empty ();
> >> +
> >>    if (inline_entry_data_table)
> >>      gcc_assert (inline_entry_data_table->is_empty ());
> >>
> >> @@ -33558,6 +33848,7 @@ dwarf2out_cc_finalize (void)
> >>    switch_text_ranges = NULL;
> >>    switch_cold_ranges = NULL;
> >>    current_unit_personality = NULL;
> >> +  btf_tag_htab = NULL;
> >>
> >>    early_dwarf = false;
> >>    early_dwarf_finished = false;
> >> diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-1.c 
> >> b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-1.c
> >> new file mode 100644
> >> index 00000000000..a1c1676a7ba
> >> --- /dev/null
> >> +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-1.c
> >> @@ -0,0 +1,11 @@
> >> +/* Test simple generation of DW_TAG_GNU_annotation DIE for
> >> +   btf_decl_tag attribute.  */
> >> +/* { dg-do compile } */
> >> +/* { dg-options "-gdwarf -dA" } */
> >> +
> >> +int *foo __attribute__((btf_decl_tag ("my_foo")));
> >> +
> >> +/* { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) 
> >> DW_TAG_GNU_annotation" 1 } } */
> >> +/* { dg-final { scan-assembler-times " DW_AT_name: \"btf_decl_tag\"" 1 } 
> >> } */
> >> +/* { dg-final { scan-assembler-times " DW_AT_const_value: \"my_foo\"" 1 } 
> >> } */
> >> +/* { dg-final { scan-assembler-times " DW_AT_GNU_annotation" 1 } } */
> >> diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-2.c 
> >> b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-2.c
> >> new file mode 100644
> >> index 00000000000..00485c000b5
> >> --- /dev/null
> >> +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-2.c
> >> @@ -0,0 +1,25 @@
> >> +/* Test dwarf generation for btf_decl_tag on struct and union members.  */
> >> +/* { dg-do compile } */
> >> +/* { dg-options "-gdwarf -dA" } */
> >> +
> >> +#define __tag1 __attribute__((btf_decl_tag ("decl1")))
> >> +#define __tag2 __attribute__((btf_decl_tag ("decl2")))
> >> +
> >> +union U {
> >> +  int i __tag1;
> >> +  unsigned char ub[4];
> >> +};
> >> +
> >> +struct S {
> >> +  union U u;
> >> +  int b __tag2;
> >> +  char *z __tag1;
> >> +};
> >> +
> >> +struct S my_s __tag1 __tag2;
> >> +
> >> +/* We must have two occurrences of one of the two annotation DIEs due to
> >> +   the different attribute sets between declarations above.  */
> >> +/* { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) 
> >> DW_TAG_GNU_annotation" 3 } } */
> >> +/* { dg-final { scan-assembler-times " DW_AT_name: \"btf_decl_tag\"" 3 } 
> >> } */
> >> +/* { dg-final { scan-assembler-times " DW_AT_GNU_annotation" 5 } } */
> >> diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-3.c 
> >> b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-3.c
> >> new file mode 100644
> >> index 00000000000..f3fad8fe3d2
> >> --- /dev/null
> >> +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-3.c
> >> @@ -0,0 +1,21 @@
> >> +/* Test dwarf generation for btf_decl_tag on functions and function args. 
> >> */
> >> +/* { dg-do compile } */
> >> +/* { dg-options "-gdwarf -dA" } */
> >> +
> >> +#define __tag1 __attribute__((btf_decl_tag ("decl1")))
> >> +#define __tag2 __attribute__((btf_decl_tag ("decl2")))
> >> +
> >> +int __tag1 __tag2 func (int arg_a __tag1, int arg_b __tag2)
> >> +{
> >> +  return arg_a * arg_b;
> >> +}
> >> +
> >> +int foo (int x) {
> >> +  return func (x, x + 1);
> >> +}
> >> +
> >> +/* In this case one of the decl tag DIEs must be duplicated due to 
> >> differing
> >> +   DW_AT_GNU_annotation chain between the three uses.  */
> >> +/* { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) 
> >> DW_TAG_GNU_annotation" 3 } } */
> >> +/* { dg-final { scan-assembler-times " DW_AT_name: \"btf_decl_tag\"" 3 } 
> >> } */
> >> +/* { dg-final { scan-assembler-times " DW_AT_GNU_annotation" 4 } } */
> >> diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-type-tag-1.c 
> >> b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-type-tag-1.c
> >> new file mode 100644
> >> index 00000000000..772aab09cfb
> >> --- /dev/null
> >> +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-type-tag-1.c
> >> @@ -0,0 +1,10 @@
> >> +/* Test simple generation for btf_type_tag attribute.  */
> >> +/* { dg-do compile } */
> >> +/* { dg-options "-gdwarf -dA" } */
> >> +
> >> +int * __attribute__((btf_type_tag("__user"))) ptr;
> >> +
> >> +/* { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) 
> >> DW_TAG_GNU_annotation" 1 } } */
> >> +/* { dg-final { scan-assembler-times " DW_AT_name: \"btf_type_tag\"" 1 } 
> >> } */
> >> +/* { dg-final { scan-assembler-times " DW_AT_const_value: \"__user\"" 1 } 
> >> } */
> >> +/* { dg-final { scan-assembler-times " DW_AT_GNU_annotation" 1 } } */
> >> diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-type-tag-2.c 
> >> b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-type-tag-2.c
> >> new file mode 100644
> >> index 00000000000..9c44e0ee0b9
> >> --- /dev/null
> >> +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-type-tag-2.c
> >> @@ -0,0 +1,31 @@
> >> +/* Test that DW_TAG_GNU_annotation DIEs for attribute btf_type_tag are 
> >> shared
> >> +   where possible.  */
> >> +/* { dg-do compile } */
> >> +/* { dg-options "-gdwarf -dA" } */
> >> +
> >> +#define __tag1 __attribute__((btf_type_tag("tag1")))
> >> +#define __tag2 __attribute__((btf_type_tag("tag2")))
> >> +
> >> +int __tag1 foo;
> >> +char * __tag1 __tag2 bar;
> >> +
> >> +struct S
> >> +{
> >> +  unsigned char bytes[8];
> >> +  unsigned long __tag1 t;
> >> +  void *ptr;
> >> +};
> >> +
> >> +struct S * __tag1 __tag2 my_S;
> >> +
> >> +/* Only 2 DW_TAG_GNU_annotation DIEs should be generated, one each for 
> >> "tag1"
> >> +   and "tag2", and they should be reused.  */
> >> +/* { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) 
> >> DW_TAG_GNU_annotation" 2 } } */
> >> +/* { dg-final { scan-assembler-times " DW_AT_name: \"btf_type_tag\"" 2 } 
> >> } */
> >> +/* { dg-final { scan-assembler-times " DW_AT_const_value: \"tag1\"" 1 } } 
> >> */
> >> +/* { dg-final { scan-assembler-times " DW_AT_const_value: \"tag2\"" 1 } } 
> >> */
> >> +
> >> +/* Each attribute-ed type shall refer via DW_AT_GNU_annotation to the
> >> +   appropriate annotation DIE, including the annotation DIE for "tag2" 
> >> which
> >> +   is always chained to the DIE for "tag1" in this construction.  */
> >> +/* { dg-final { scan-assembler-times " DW_AT_GNU_annotation" 5 } } */
> >> diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-type-tag-3.c 
> >> b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-type-tag-3.c
> >> new file mode 100644
> >> index 00000000000..d02144c8004
> >> --- /dev/null
> >> +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-type-tag-3.c
> >> @@ -0,0 +1,15 @@
> >> +/* Test dwarf generation for btf_type_tag with cv-quals and typedefs.  */
> >> +/* { dg-do compile } */
> >> +/* { dg-options "-gdwarf -dA" } */
> >> +
> >> +#define __tag1 __attribute__((btf_type_tag ("tag1")))
> >> +#define __tag2 __attribute__((btf_type_tag ("tag2")))
> >> +
> >> +typedef const int foo;
> >> +typedef int __tag1 bar;
> >> +
> >> +foo __tag2 x;
> >> +const bar y;
> >> +
> >> +/* { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) 
> >> DW_TAG_GNU_annotation" 2 } } */
> >> +/* { dg-final { scan-assembler-times " DW_AT_name: \"btf_type_tag\"" 2 } 
> >> } */
> >> diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-type-tag-4.c 
> >> b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-type-tag-4.c
> >> new file mode 100644
> >> index 00000000000..7205ef2c9a3
> >> --- /dev/null
> >> +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-type-tag-4.c
> >> @@ -0,0 +1,34 @@
> >> +/* Test generating annotation DIEs for struct/union/enum types.  */
> >> +/* { dg-do compile } */
> >> +/* { dg-options "-gdwarf -dA" } */
> >> +
> >> +enum E
> >> +{
> >> +  ONE,
> >> +  TWO
> >> +} __attribute__((btf_type_tag("foo")));
> >> +
> >> +enum E some_e;
> >> +
> >> +struct S
> >> +{
> >> +  int i;
> >> +  char c;
> >> +} __attribute__((btf_type_tag("foo")));
> >> +
> >> +typedef struct S S1;
> >> +S1 plain_s1;
> >> +const S1 const_s1;
> >> +
> >> +union U
> >> +{
> >> +  int x;
> >> +  char y;
> >> +} __attribute__((btf_type_tag("foo")));
> >> +
> >> +volatile union U volatile_u;
> >> +
> >> +/* One annotation DIE may be shared by all three annotated types.  */
> >> +/* { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) 
> >> DW_TAG_GNU_annotation" 1 } } */
> >> +/* { dg-final { scan-assembler-times " DW_AT_name: \"btf_type_tag\"" 1 } 
> >> } */
> >> +/* { dg-final { scan-assembler-times " DW_AT_GNU_annotation" 3 } } */
> >> diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-type-tag-5.c 
> >> b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-type-tag-5.c
> >> new file mode 100644
> >> index 00000000000..1a6b29f99a1
> >> --- /dev/null
> >> +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-type-tag-5.c
> >> @@ -0,0 +1,10 @@
> >> +/* Test generation for btf_type_tag attribute on array type.  */
> >> +/* { dg-do compile } */
> >> +/* { dg-options "-gdwarf -dA" } */
> >> +
> >> +int arr[8] __attribute__((btf_type_tag("tagged_arr")));
> >> +
> >> +/* { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) 
> >> DW_TAG_GNU_annotation" 1 } } */
> >> +/* { dg-final { scan-assembler-times " DW_AT_name: \"btf_type_tag\"" 1 } 
> >> } */
> >> +/* { dg-final { scan-assembler-times " DW_AT_const_value: \"tagged_arr\"" 
> >> 1 } } */
> >> +/* { dg-final { scan-assembler-times " DW_AT_GNU_annotation" 1 } } */
> >> diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-type-tag-6.c 
> >> b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-type-tag-6.c
> >> new file mode 100644
> >> index 00000000000..11fc9036b8a
> >> --- /dev/null
> >> +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-type-tag-6.c
> >> @@ -0,0 +1,27 @@
> >> +/* Test generation for btf_type_tag attribute when applied to struct/union
> >> +   types after definition.  Attributes applied after definition will be
> >> +   ignored, so DW_TAG_GNU_annotations shall be generated.  */
> >> +/* { dg-do compile } */
> >> +/* { dg-options "-gdwarf -dA" } */
> >> +
> >> +struct foo
> >> +{
> >> +  int a;
> >> +  char c;
> >> +};
> >> +
> >> +struct foo __attribute__((btf_type_tag ("tag1"))) x;  /* { dg-warning 
> >> "ignoring attribute" } */
> >> +typedef const struct foo c_foo;
> >> +c_foo __attribute__((btf_type_tag ("tag2"))) y; /* { dg-warning "ignoring 
> >> attribute" } */
> >> +
> >> +union bar
> >> +{
> >> +  int s;
> >> +  unsigned int u;
> >> +};
> >> +
> >> +typedef union bar __attribute__((btf_type_tag("tag3"))) tag_bar; /* { 
> >> dg-warning "ignoring attribute" } */
> >> +const tag_bar z;
> >> +
> >> +/* { dg-final { scan-assembler-not "DIE \\(\[^\n\]*\\) 
> >> DW_TAG_GNU_annotation" } } */
> >> +/* { dg-final { scan-assembler-not " DW_AT_GNU_annotation" } } */
> >> diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-type-tag-7.c 
> >> b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-type-tag-7.c
> >> new file mode 100644
> >> index 00000000000..5b3d45d5e7a
> >> --- /dev/null
> >> +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-type-tag-7.c
> >> @@ -0,0 +1,25 @@
> >> +/* Test generation for btf_type_tag attribute for pointer typedef with
> >> +   tags appearing on both the typedef and the usage of the tyepdef.  */
> >> +/* { dg-do compile } */
> >> +/* { dg-options "-gdwarf -dA" } */
> >> +
> >> +#define __tag1 __attribute__((btf_type_tag ("tag1")))
> >> +#define __tag2 __attribute__((btf_type_tag ("tag2")))
> >> +
> >> +typedef int __tag1 foo;
> >> +
> >> +foo a;
> >> +foo __tag2 b;
> >> +
> >> +/* { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) 
> >> DW_TAG_GNU_annotation" 2 } } */
> >> +/* { dg-final { scan-assembler-times " DW_AT_name: \"btf_type_tag\"" 2 } 
> >> } */
> >> +
> >> +/* Due to an ambiguity in the tree attribute list, it is not currently 
> >> possible
> >> +   to distinguish with certaianty whether "tag1" appears to the left or 
> >> right
> >> +   of "foo" in the declaration of "b" above.  This means that the DIE for
> >> +   "tag1" is also referred in the AT_GNU_annotation chain of the duplicate
> >> +   typedef DIE annotated wtih "tag2", for a total of 3 
> >> AT_GNU_annotations.  */
> >> +/* { dg-final { scan-assembler-times " DW_AT_GNU_annotation" 3 } } */
> >> +
> >> +/* A duplicate typedef die must be created for the tagged use in 'b'.  */
> >> +/* { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) DW_TAG_typedef" 
> >> 2 } } */
> >> diff --git a/include/dwarf2.def b/include/dwarf2.def
> >> index 989f078041d..37b8d6b99d0 100644
> >> --- a/include/dwarf2.def
> >> +++ b/include/dwarf2.def
> >> @@ -174,6 +174,9 @@ DW_TAG (DW_TAG_GNU_formal_parameter_pack, 0x4108)
> >>     are properly part of DWARF 5.  */
> >>  DW_TAG (DW_TAG_GNU_call_site, 0x4109)
> >>  DW_TAG (DW_TAG_GNU_call_site_parameter, 0x410a)
> >> +
> >> +DW_TAG (DW_TAG_GNU_annotation, 0x6001)
> >> +
> >>  /* Extensions for UPC.  See: http://dwarfstd.org/doc/DWARF4.pdf.  */
> >>  DW_TAG (DW_TAG_upc_shared_type, 0x8765)
> >>  DW_TAG (DW_TAG_upc_strict_type, 0x8766)
> >> @@ -456,6 +459,7 @@ DW_AT (DW_AT_GNU_pubtypes, 0x2135)
> >>  DW_AT (DW_AT_GNU_discriminator, 0x2136)
> >>  DW_AT (DW_AT_GNU_locviews, 0x2137)
> >>  DW_AT (DW_AT_GNU_entry_view, 0x2138)
> >> +DW_AT (DW_AT_GNU_annotation, 0x2139)
> >>  /* VMS extensions.  */
> >>  DW_AT (DW_AT_VMS_rtnbeg_pd_address, 0x2201)
> >>  /* GNAT extensions.  */
> >> --
> >> 2.47.2
> >>
>

Reply via email to