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 > >> >