@@ -3696,6 +3696,32 @@ 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;
+};
+
+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
@@ -13649,6 +13675,168 @@ long_double_as_float128 (tree type)
return NULL_TREE;
}
+
+hashval_t
+annotation_node_hasher::hash (struct annotation_node *node)
+{
+ return node->hash;
+}
+
+bool
+annotation_node_hasher::equal (const struct annotation_node *node1,
+ const struct annotation_node *node2)
+{
+ return (node1->hash == node2->hash);
+}
+
+/* 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_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_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.
+ 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_die_ref (die, DW_AT_GNU_annotation, tag_die);
+
+ return tag_die;
+}
+
+static void
+gen_btf_type_tag_dies (tree t, tree attr, dw_die_ref target,
+ dw_die_ref context_die)
+{
+ if (t == NULL_TREE || !TYPE_P (t) || !target)
+ return;
+
+ gen_btf_tag_dies (attr, target, context_die);
+}
+
+static void
+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);
+
+ /* Strip the decl tag attribute once we have created the annotation DIEs
+ to avoid attempting process it multiple times. */
+ DECL_ATTRIBUTES (t)
+ = remove_attribute ("btf_decl_tag", DECL_ATTRIBUTES (t));
+}
+
/* 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
@@ -13774,10 +13962,44 @@ 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);
+ {
+ if (lookup_attribute ("btf_type_tag", TYPE_ATTRIBUTES (type)))
+ {
+ /* Use of a typedef with additional btf_type_tags. Create
+ a distinct typedef DIE for this version of the named type
+ so that the btf_type_tag annotations may be attached to
+ it without affecting other users of the plain typedef. */
+ tree tags = lookup_attribute ("btf_type_tag",
+ TYPE_ATTRIBUTES (type));
+ tree dtags = lookup_attribute ("btf_type_tag",
+ TYPE_ATTRIBUTES (dtype));
+
+ /* Remove type tags before the recursive call to avoid
+ processing the same attribute multiple times. */
+ TYPE_ATTRIBUTES (type)
+ = remove_attribute ("btf_type_tag", TYPE_ATTRIBUTES (type));
+
+ dw_die_ref mod_die = modified_type_die (dtype, cv_quals,
+ reverse, context_die);
+
+ /* Create a new typedef DIE since the btf_type_tag-ed use of
+ the typedef has really created a distinct type. */
+ if (!attribute_list_equal (tags, dtags))
+ {
+ 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);
+ }
+
+ gen_btf_type_tag_dies (type, tags, 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);
+ }
/* Else cv-qualified version of named type; fall through. */
}
}
@@ -13878,6 +14100,18 @@ modified_type_die (tree type, int cv_quals, bool reverse,
first_quals |= dwarf_qual_info[i].q;
}
}
+ else if (lookup_attribute ("btf_type_tag", TYPE_ATTRIBUTES (type)))
+ {
+ /* Remove type tags before the recursive call to avoid processing the
+ same attribute multiple times. */
+ tree attr = lookup_attribute ("btf_type_tag", TYPE_ATTRIBUTES (type));
+ TYPE_ATTRIBUTES (type) = remove_attribute ("btf_type_tag",
+ TYPE_ATTRIBUTES (type));
+ dw_die_ref mod_die = modified_type_die (type, cv_quals, reverse,
+ context_die);
+ gen_btf_type_tag_dies (type, attr, mod_die, context_die);
+ return mod_die;
+ }
else if (code == POINTER_TYPE || code == REFERENCE_TYPE)
{
dwarf_tag tag = DW_TAG_pointer_type;
@@ -23090,6 +23324,8 @@ gen_formal_parameter_die (tree node, tree origin, bool emit_name_p,
else
{
add_child_die (context_die, parm_die);
+
+ gen_btf_decl_tag_dies (node_or_origin, parm_die, context_die);
return parm_die;
}
}
@@ -23158,6 +23394,8 @@ gen_formal_parameter_die (tree node, tree origin, bool emit_name_p,
gcc_unreachable ();
}
+ gen_btf_decl_tag_dies (node_or_origin, parm_die, context_die);
+
return parm_die;
}
@@ -27342,6 +27580,9 @@ gen_decl_die (tree decl, tree origin, struct vlr_context *ctx,
break;
}
+ gen_btf_decl_tag_dies (decl_or_origin, lookup_decl_die (decl_or_origin),
+ context_die);
+
return NULL;
}
@@ -33245,6 +33486,9 @@ dwarf2out_early_finish (const char *filename)
print_die (comp_unit_die (), dump_file);
}
+ if (btf_tag_htab)
+ btf_tag_htab->empty ();
+
/* Generate CTF/BTF debug info. */
if ((ctf_debug_info_level > CTFINFO_LEVEL_NONE
|| btf_debuginfo_p ()) && lang_GNU_C ())
@@ -33440,6 +33684,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;
new file mode 100644
@@ -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 } } */
new file mode 100644
@@ -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 occurrances 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 } } */
new file mode 100644
@@ -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 } } */
new file mode 100644
@@ -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 } } */
new file mode 100644
@@ -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 } } */
new file mode 100644
@@ -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 } } */
@@ -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)
@@ -453,6 +456,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. */