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. 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; + + 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) { 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