@@ -141,6 +141,8 @@ get_btf_kind (uint32_t ctf_kind)
case CTF_K_VOLATILE: return BTF_KIND_VOLATILE;
case CTF_K_CONST: return BTF_KIND_CONST;
case CTF_K_RESTRICT: return BTF_KIND_RESTRICT;
+ case CTF_K_DECL_TAG: return BTF_KIND_DECL_TAG;
+ case CTF_K_TYPE_TAG: return BTF_KIND_TYPE_TAG;
default:;
}
return BTF_KIND_UNKN;
@@ -217,6 +219,7 @@ btf_calc_num_vbytes (ctf_dtdef_ref dtd)
case BTF_KIND_CONST:
case BTF_KIND_RESTRICT:
case BTF_KIND_FUNC:
+ case BTF_KIND_TYPE_TAG:
/* These kinds have no vlen data. */
break;
@@ -256,6 +259,10 @@ btf_calc_num_vbytes (ctf_dtdef_ref dtd)
vlen_bytes += vlen * sizeof (struct btf_var_secinfo);
break;
+ case BTF_KIND_DECL_TAG:
+ vlen_bytes += sizeof (struct btf_decl_tag);
+ break;
+
default:
break;
}
@@ -452,6 +459,20 @@ btf_asm_type (ctf_dtdef_ref dtd)
and should write 0. */
dw2_asm_output_data (4, 0, "(unused)");
return;
+ case BTF_KIND_DECL_TAG:
+ {
+ if (dtd->ref_type)
+ break;
+ else if (dtd->dtd_u.dtu_tag.ref_var)
+ {
+ /* ref_type is NULL for decl tag attached to a variable. */
+ ctf_dvdef_ref dvd = dtd->dtd_u.dtu_tag.ref_var;
+ dw2_asm_output_data (4, dvd->dvd_id,
+ "btt_type: (BTF_KIND_VAR '%s')",
+ dvd->dvd_name);
+ return;
+ }
+ }
default:
break;
}
@@ -801,6 +822,12 @@ output_asm_btf_vlen_bytes (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
at this point. */
gcc_unreachable ();
+ case BTF_KIND_DECL_TAG:
+ dw2_asm_output_data (4, dtd->dtd_u.dtu_tag.component_idx,
+ "component_idx=%d",
+ dtd->dtd_u.dtu_tag.component_idx);
+ break;
+
default:
/* All other BTF type kinds have no variable length data. */
break;
@@ -851,6 +878,20 @@ output_btf_func_types (void)
btf_asm_func_type (ref);
}
+static void
+output_btf_tags (ctf_container_ref ctfc)
+{
+ /* If pruning, tags which are not pruned have already been added to
+ the used list and output by output_btf_types. */
+ if (debug_prune_btf)
+ return;
+
+ ctf_dtdef_ref dtd;
+ unsigned i;
+ FOR_EACH_VEC_ELT (*ctfc->ctfc_tags, i, dtd)
+ output_asm_btf_type (ctfc, dtd);
+}
+
/* Output all BTF_KIND_DATASEC records. */
static void
@@ -869,6 +910,7 @@ btf_output (ctf_container_ref ctfc)
output_btf_types (ctfc);
output_btf_vars (ctfc);
output_btf_func_types ();
+ output_btf_tags (ctfc);
output_btf_datasec_types ();
output_btf_strs (ctfc);
}
@@ -985,7 +1027,8 @@ static vec<struct btf_fixup> fixups;
is created and emitted. This vector stores them. */
static GTY (()) vec<ctf_dtdef_ref, va_gc> *forwards;
-/* Recursively add type DTD and any types it references to the used set.
+/* Implementation of btf_add_used_type.
+ Recursively add type DTD and any types it references to the used set.
Return a type that should be used for references to DTD - usually DTD itself,
but may be NULL if DTD corresponds to a type which will not be emitted.
CHECK_PTR is true if one of the predecessors in recursive calls is a struct
@@ -996,8 +1039,8 @@ static GTY (()) vec<ctf_dtdef_ref, va_gc> *forwards;
CREATE_FIXUPS is false. */
static ctf_dtdef_ref
-btf_add_used_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd,
- bool check_ptr, bool seen_ptr, bool create_fixups)
+btf_add_used_type_1 (ctf_container_ref ctfc, ctf_dtdef_ref dtd,
+ bool check_ptr, bool seen_ptr, bool create_fixups)
{
if (dtd == NULL)
return NULL;
@@ -1029,8 +1072,9 @@ btf_add_used_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd,
fixups.unordered_remove (i);
/* Add the concrete base type. */
- dtd->ref_type = btf_add_used_type (ctfc, dtd->ref_type, check_ptr,
- seen_ptr, create_fixups);
+ dtd->ref_type = btf_add_used_type_1 (ctfc, dtd->ref_type,
+ check_ptr, seen_ptr,
+ create_fixups);
return dtd;
}
default:
@@ -1044,8 +1088,8 @@ btf_add_used_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd,
the reference to the bitfield. The slice type won't be emitted,
but we need the information in it when writing out the bitfield
encoding. */
- btf_add_used_type (ctfc, dtd->dtd_u.dtu_slice.cts_type,
- check_ptr, seen_ptr, create_fixups);
+ btf_add_used_type_1 (ctfc, dtd->dtd_u.dtu_slice.cts_type,
+ check_ptr, seen_ptr, create_fixups);
return dtd;
}
@@ -1069,7 +1113,11 @@ btf_add_used_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd,
case BTF_KIND_INT:
case BTF_KIND_FLOAT:
case BTF_KIND_FWD:
- /* Leaf kinds which do not refer to any other types. */
+ case BTF_KIND_DECL_TAG:
+ /* Leaf kinds which do not refer to any other types.
+ DECL_TAG is a special case: we treat it as though it does not refer
+ to any other types, since we only want the DECL_TAG to be added if
+ the type to which it refers has already been added. */
break;
case BTF_KIND_FUNC:
@@ -1082,6 +1130,7 @@ btf_add_used_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd,
case BTF_KIND_CONST:
case BTF_KIND_VOLATILE:
case BTF_KIND_RESTRICT:
+ case BTF_KIND_TYPE_TAG:
{
/* These type kinds refer to exactly one other type. */
if (check_ptr && !seen_ptr)
@@ -1106,18 +1155,18 @@ btf_add_used_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd,
}
/* Add the type to which this type refers. */
- dtd->ref_type = btf_add_used_type (ctfc, dtd->ref_type, check_ptr,
- seen_ptr, create_fixups);
+ dtd->ref_type = btf_add_used_type_1 (ctfc, dtd->ref_type, check_ptr,
+ seen_ptr, create_fixups);
break;
}
case BTF_KIND_ARRAY:
{
/* Add element and index types. */
ctf_arinfo_t *arr = &(dtd->dtd_u.dtu_arr);
- arr->ctr_contents = btf_add_used_type (ctfc, arr->ctr_contents, false,
- false, create_fixups);
- arr->ctr_index = btf_add_used_type (ctfc, arr->ctr_index, false, false,
- create_fixups);
+ arr->ctr_contents = btf_add_used_type_1 (ctfc, arr->ctr_contents,
+ false, false, create_fixups);
+ arr->ctr_index = btf_add_used_type_1 (ctfc, arr->ctr_index, false,
+ false, create_fixups);
break;
}
case BTF_KIND_STRUCT:
@@ -1133,8 +1182,8 @@ btf_add_used_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd,
/* Add member type for struct/union members. For enums, only the
enumerator names are needed. */
if (kind == BTF_KIND_STRUCT || kind == BTF_KIND_UNION)
- dmd->dmd_type = btf_add_used_type (ctfc, dmd->dmd_type, true,
- false, create_fixups);
+ dmd->dmd_type = btf_add_used_type_1 (ctfc, dmd->dmd_type, true,
+ false, create_fixups);
ctf_add_string (ctfc, dmd->dmd_name, &(dmd->dmd_name_offset),
CTF_STRTAB);
}
@@ -1143,16 +1192,17 @@ btf_add_used_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd,
case BTF_KIND_FUNC_PROTO:
{
/* Add return type. */
- dtd->ref_type = btf_add_used_type (ctfc, dtd->ref_type, false, false,
- create_fixups);
+ dtd->ref_type = btf_add_used_type_1 (ctfc, dtd->ref_type, false, false,
+ create_fixups);
/* Add arg types. */
ctf_func_arg_t * farg;
for (farg = dtd->dtd_u.dtu_argv;
farg != NULL; farg = (ctf_func_arg_t *) ctf_farg_list_next (farg))
{
- farg->farg_type = btf_add_used_type (ctfc, farg->farg_type, false,
- false, create_fixups);
+ farg->farg_type = btf_add_used_type_1 (ctfc, farg->farg_type,
+ false, false,
+ create_fixups);
/* Note: argument names are stored in the auxilliary string table,
since CTF does not include arg names. That table has not been
cleared, so no need to re-add argument names here. */
@@ -1166,6 +1216,16 @@ btf_add_used_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd,
return dtd;
}
+/* Recursively add type DTD and any types it references to the used set.
+ Return a type that should be used for references to DTD - usually DTD itself,
+ but may be NULL if DTD corresponds to a type which will not be emitted. */
+
+static ctf_dtdef_ref
+btf_add_used_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
+{
+ return btf_add_used_type_1 (ctfc, dtd, false, false, true);
+}
+
/* Initial entry point of BTF generation, called at early_finish () after
CTF information has possibly been output. Translate all CTF information
to BTF, and do any processing that must be done early, such as creating
@@ -1402,7 +1462,7 @@ btf_add_vars (ctf_container_ref ctfc)
ctf_dmdef_t *dmd;
for (dmd = dtd->dtd_u.dtu_members;
dmd != NULL; dmd = (ctf_dmdef_t *) ctf_dmd_list_next (dmd))
- btf_add_used_type (ctfc, dmd->dmd_type, false, false, true);
+ btf_add_used_type (ctfc, dmd->dmd_type);
}
}
}
@@ -1488,6 +1548,50 @@ btf_assign_var_ids (ctf_container_ref ctfc)
}
}
+/* Assign BTF IDs for type and decl tags and account for their size. */
+
+static void
+btf_assign_tag_ids (ctf_container_ref ctfc)
+{
+ /* Both decl and type tags may be pruned if the types/decls to which they
+ refer are pruned. This is handled in collect_pruned_types, and through
+ that process they have also been assigned ids already. */
+ if (debug_prune_btf)
+ return;
+
+ size_t num_tags = vec_safe_length (ctfc->ctfc_tags);
+ if (num_tags == 0)
+ return;
+
+ unsigned int i;
+ ctf_dtdef_ref dtd;
+ FOR_EACH_VEC_ELT (*ctfc->ctfc_tags, i, dtd)
+ {
+ /* Assign BTF id. */
+ ctf_id_t id = ctfc->ctfc_nextid++;
+ gcc_assert (id <= BTF_MAX_TYPE);
+ dtd->dtd_type = id;
+
+ /* Tags on functions will have a ref_type pointing to the
+ FUNC_PROTO, we want them to point the FUNC record instead. */
+ ctf_dtdef_ref *pdtd = NULL;
+ if (dtd->ref_type && (pdtd = func_map->get (dtd->ref_type)) != NULL)
+ {
+ dtd->ref_type = *pdtd;
+ }
+
+ /* Strings for tags are stored in the auxilliary strtab, which is
+ concatenated after the regular strtab. ctti_name only accounts
+ for offset in the auxilliary strtab until this point. */
+ dtd->dtd_data.ctti_name += ctfc_get_strtab_len (ctfc, CTF_STRTAB);
+
+ ctfc->ctfc_num_types++;
+
+ if (btf_dtd_kind (dtd) == BTF_KIND_DECL_TAG)
+ ctfc->ctfc_num_vlen_bytes += sizeof (struct btf_decl_tag);
+ }
+}
+
/* Assign BTF IDs for datasec records and account for their size. */
static void
@@ -1522,7 +1626,7 @@ btf_mark_type_used (tree t)
if (!dtd)
return;
- btf_add_used_type (ctfc, dtd, false, false, true);
+ btf_add_used_type (ctfc, dtd);
}
/* Callback used for assembling the only-used-types list. Note that this is
@@ -1549,7 +1653,7 @@ btf_collect_pruned_types (ctf_container_ref ctfc)
size_t i;
FOR_EACH_VEC_ELT (*funcs, i, dtd)
{
- btf_add_used_type (ctfc, dtd->ref_type, false, false, true);
+ btf_add_used_type (ctfc, dtd->ref_type);
ctf_add_string (ctfc, dtd->dtd_name, &(dtd->dtd_data.ctti_name),
CTF_STRTAB);
}
@@ -1558,10 +1662,33 @@ btf_collect_pruned_types (ctf_container_ref ctfc)
for (i = 0; i < ctfc->ctfc_vars_list_count; i++)
{
ctf_dvdef_ref dvd = ctfc->ctfc_vars_list[i];
- btf_add_used_type (ctfc, dvd->dvd_type, false, false, true);
+ btf_add_used_type (ctfc, dvd->dvd_type);
ctf_add_string (ctfc, dvd->dvd_name, &(dvd->dvd_name_offset), CTF_STRTAB);
}
+ /* Used type tags will be added by recursive btf_add_used_type calls above.
+ For decl tags, scan the list and only add those decl tags whose referent
+ types are marked as used. We may have pruned a struct type with members
+ annotated by a decl tag. */
+ FOR_EACH_VEC_ELT (*ctfc->ctfc_tags, i, dtd)
+ {
+ /* Only add decl tags whose referent types have not been pruned.
+ Variables are never pruned, so decl tags on variables are always
+ used. */
+ if (btf_dtd_kind (dtd) == BTF_KIND_DECL_TAG
+ && ((dtd->ref_type && btf_used_types->contains (dtd->ref_type))
+ || (dtd->dtd_u.dtu_tag.ref_var)))
+ btf_add_used_type (ctfc, dtd);
+
+ /* Tags on functions or function args will have a ref_type pointing to the
+ FUNC_PROTO, we want them to point the FUNC record instead. */
+ ctf_dtdef_ref *pdtd = NULL;
+ if (dtd->ref_type
+ && btf_used_types->contains (dtd->ref_type)
+ && (pdtd = func_map->get (dtd->ref_type)) != NULL)
+ dtd->ref_type = *pdtd;
+ }
+
/* Process fixups. If the base type was never added, create a forward for it
and adjust the reference to point to that. If it was added, then nothing
needs to change. */
@@ -1634,6 +1761,7 @@ btf_finish (void)
btf_assign_var_ids (tu_ctfc);
btf_assign_func_ids (tu_ctfc);
+ btf_assign_tag_ids (tu_ctfc);
btf_assign_datasec_ids (tu_ctfc);
/* Finally, write out the complete .BTF section. */
new file mode 100644
@@ -0,0 +1,14 @@
+/* Test simple BTF decl tag generation for variables. */
+/* { dg-do compile } */
+/* { dg-options "-O0 -gbtf -dA" } */
+
+#define __tag1 __attribute__((btf_decl_tag ("decl1")))
+#define __tag2 __attribute__((btf_decl_tag ("decl2")))
+#define __tag3 __attribute__((btf_decl_tag ("decl3")))
+
+int x __tag1 __tag2;
+int y __tag1;
+
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 'decl1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_VAR 'x'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=-1" 1} } */
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 'decl2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_VAR 'x'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=-1" 1} } */
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 'decl1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_VAR 'y'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=-1" 1} } */
new file mode 100644
@@ -0,0 +1,22 @@
+/* Test BTF decl tag generation for structs. */
+/* { dg-do compile } */
+/* { dg-options "-O0 -gbtf -dA" } */
+
+#define __tag1 __attribute__((btf_decl_tag ("decl1")))
+#define __tag2 __attribute__((btf_decl_tag ("decl2")))
+#define __tag3 __attribute__((btf_decl_tag ("decl3")))
+
+struct Foo {
+ int a;
+ int b __tag3 __tag2;
+ char *z __tag1;
+};
+
+struct Foo f __tag1 __tag2;
+
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 'decl2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_STRUCT 'Foo'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=1" 1} } */
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 'decl3'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_STRUCT 'Foo'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=1" 1} } */
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 'decl1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_STRUCT 'Foo'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=2" 1} } */
+
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 'decl1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_VAR 'f'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=-1" 1} } */
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 'decl2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_VAR 'f'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=-1" 1} } */
new file mode 100644
@@ -0,0 +1,22 @@
+/* Test BTF decl tag generation for functions and function args. */
+/* { dg-do compile } */
+/* { dg-options "-O0 -gbtf -dA" } */
+
+#define __tag1 __attribute__((btf_decl_tag ("decl1")))
+#define __tag2 __attribute__((btf_decl_tag ("decl2")))
+#define __tag3 __attribute__((btf_decl_tag ("decl3")))
+
+int __tag1 __tag2 func (int arg_a __tag3 __tag1, int arg_b __tag2)
+{
+ return arg_a * arg_b;
+}
+
+int foo (int x) {
+ return func (x, x + 1);
+}
+
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 'decl1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_FUNC 'func'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=-1" 1} } */
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 'decl2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_FUNC 'func'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=-1" 1} } */
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 'decl1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_FUNC 'func'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=0" 1} } */
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 'decl3'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_FUNC 'func'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=0" 1} } */
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 'decl2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_FUNC 'func'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=1" 1} } */
new file mode 100644
@@ -0,0 +1,34 @@
+/* Test BTF decl tag generation with BTF pruning. */
+/* { dg-do compile } */
+/* { dg-options "-O0 -gbtf -gprune-btf -dA" } */
+
+#define __decl1 __attribute__((btf_decl_tag ("decl1")))
+#define __decl2 __attribute__((btf_decl_tag ("decl2")))
+#define __decl3 __attribute__((btf_decl_tag ("decl3")))
+
+struct S {
+ /* This tag on S.v shall not be emitted, because struct S is pruned and
+ replaced with a FWD, which does not hold any member info. */
+ int v __decl3;
+ int w;
+};
+
+struct T {
+ int a;
+ struct S *s __decl1;
+ int c __decl2;
+};
+
+struct T t __decl1;
+
+int __decl1 func (struct T *t __decl2)
+{
+ return t->a + t->c;
+}
+
+/* { dg-final { scan-assembler-not " BTF_KIND_DECL_TAG 'decl3'" } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 'decl1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_STRUCT 'T'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=1" 1} } */
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 'decl2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_STRUCT 'T'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=2" 1} } */
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 'decl1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_VAR 't'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=-1" 1} } */
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 'decl1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_FUNC 'func'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=-1" 1} } */
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 'decl2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_FUNC 'func'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=0" 1} } */
new file mode 100644
@@ -0,0 +1,27 @@
+/* Test simple generation of BTF type tags. */
+/* { dg-do compile } */
+/* { dg-options "-O0 -gbtf -dA" } */
+
+#define __tag1 __attribute__((btf_type_tag("type1")))
+#define __tag2 __attribute__((btf_type_tag("type2")))
+#define __tag3 __attribute__((btf_type_tag("type3")))
+
+int __tag1 __tag2 x;
+int __tag1 y;
+
+struct Foo {
+ char a;
+ int b;
+};
+
+struct Foo * __tag1 __tag3 f;
+
+/* { dg-final { scan-assembler-times " BTF_KIND_VAR 'x'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG 'type2'\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 'type2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG 'type1'\\)" 1} } */
+
+/* { dg-final { scan-assembler-times " BTF_KIND_VAR 'y'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG 'type1'\\)" 1 } } */
+/* { dg-final { scan-assembler " BTF_KIND_TYPE_TAG 'type1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_INT" } } */
+
+/* { dg-final { scan-assembler-times " BTF_KIND_VAR 'f'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG 'type3'\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 'type3'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG 'type1'\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 'type1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_PTR" 1 } } */
new file mode 100644
@@ -0,0 +1,17 @@
+/* Test BTF type tag generation with cv-quals.
+ BTF format requires that type tags precede cv-quals on a given
+ type in the type chain. */
+/* { dg-do compile } */
+/* { dg-options "-O0 -gbtf -dA" } */
+
+#define __tag1 __attribute__((btf_type_tag("type1")))
+#define __tag2 __attribute__((btf_type_tag("type2")))
+#define __tag3 __attribute__((btf_type_tag("type3")))
+
+/* var (a) -> tag2 -> tag1 -> const -> int */
+const int __tag1 __tag2 a;
+
+/* { dg-final { scan-assembler-times " BTF_KIND_VAR 'a'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG 'type2'\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 'type2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG 'type1'\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 'type1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_CONST ''\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_CONST ''(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_INT" 1 } } */
new file mode 100644
@@ -0,0 +1,21 @@
+/* Test BTF type tag generation with typedefs. */
+/* { dg-do compile } */
+/* { dg-options "-O0 -gbtf -dA" } */
+
+#define __tag1 __attribute__((btf_type_tag("type1")))
+#define __tag2 __attribute__((btf_type_tag("type2")))
+#define __tag3 __attribute__((btf_type_tag("type3")))
+
+typedef const int foo;
+typedef int __tag1 bar;
+
+foo __tag2 x;
+const bar y;
+
+/* { dg-final { scan-assembler-times " BTF_KIND_VAR 'x'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG 'type2'\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 'type2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPEDEF 'foo'\\)" 1 } } */
+
+/* { dg-final { scan-assembler-times " BTF_KIND_VAR 'y'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_CONST" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_CONST ''(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPEDEF 'bar'\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPEDEF 'bar'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG 'type1'\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 'type1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_INT" 1 } } */
new file mode 100644
@@ -0,0 +1,25 @@
+/* Test BTF type tag generation with BTF pruning. */
+/* { dg-do compile } */
+/* { dg-options "-O0 -gbtf -gprune-btf -dA" } */
+
+#define __tag1 __attribute__((btf_type_tag("type1")))
+#define __tag2 __attribute__((btf_type_tag("type2")))
+#define __tag3 __attribute__((btf_type_tag("type3")))
+
+struct S {
+ int v ;
+ /* This tag on S.w shall not be emitted because struct S is pruned. */
+ int __tag3 w;
+};
+
+struct T {
+ int __tag1 a;
+ struct S * __tag2 s;
+ int c;
+};
+
+struct T t;
+
+/* { dg-final { scan-assembler-not " BTF_KIND_TYPE_TAG 'type3'" } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 'type1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_INT" 1} } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 'type2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_PTR" 1} } */
new file mode 100644
@@ -0,0 +1,23 @@
+/* Test BTF type tag generation using C2x standard attribute syntax.
+ Note: in more complicated cases the __attribute__ syntax causes BTF type tags
+ to "slide around" in defined, but often unexpected ways. */
+
+/* { dg-do compile } */
+/* { dg-options "-O0 -gbtf -dA" } */
+
+#define __tag1 [[gnu::btf_type_tag ("type1")]]
+#define __tag2 [[gnu::btf_type_tag ("type2")]]
+#define __tag3 [[gnu::btf_type_tag ("type3")]]
+
+/* var (z) -> tag2 -> tag3 -> const -> ptr -> tag2 -> ptr -> tag1 -> volatile -> int */
+volatile int __tag1 * __tag2 * __tag3 __tag2 const z;
+
+/* { dg-final { scan-assembler-times " BTF_KIND_VAR 'z'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG 'type2'\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 'type2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG 'type3'\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 'type3'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_CONST" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_CONST ''(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_PTR" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_PTR ''(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG 'type2'\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 'type2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_PTR" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_PTR ''(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG 'type1'\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 'type1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_VOLATILE ''\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_VOLATILE ''(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_INT" 1 } } */
@@ -114,6 +114,8 @@ struct btf_type
#define BTF_KIND_VAR 14 /* Variable. */
#define BTF_KIND_DATASEC 15 /* Section such as .bss or .data. */
#define BTF_KIND_FLOAT 16 /* Floating point. */
+#define BTF_KIND_DECL_TAG 17 /* Declaration tag. */
+#define BTF_KIND_TYPE_TAG 18 /* Type tag. */
#define BTF_KIND_ENUM64 19 /* Enumeration up to 64 bits. */
#define BTF_KIND_MAX BTF_KIND_ENUM64
#define NR_BTF_KINDS (BTF_KIND_MAX + 1)
@@ -227,6 +229,18 @@ struct btf_enum64
uint32_t val_hi32; /* high 32-bit value for a 64-bit value Enumerator */
};
+/* BTF_KIND_DECL_TAG is followed by a single struct btf_decl_tag, which
+ describes the item to which the tag applies:
+ - If component_idx == -1, then the tag applies to item referred to by
+ the type_id.
+ - Otherwise, the tag applies to the struct or union member, or function
+ argument of the type referred to by type_id with the 0-based index
+ given by component_idx. */
+struct btf_decl_tag
+{
+ int32_t component_idx;
+};
+
#ifdef __cplusplus
}
#endif