Currently btf_type_tag is only allowed on pointer types. Emil wanted
this to be be attachable to typedefs too (his original request was for
derived types, but that is next step/patch).
e.g.
typedef unsigned int __attribute__((btf_type_tag ("td_tag"))) uint_t;
uint_t u;
with -gbtf produced
BTF_KIND_TYPEDEF 'uint_t' -> BTF_KIND_INT 'unsigned int'
losing the tag.
Turns out this was already supported by the C front end and recorded
correctly in DWARF as well (DW_TAG_GNU_annotation / DW_AT_GNU_annotation),
but was silently dropped when generating BTF because handle_ctf_type_tags()
was invoked solely from gen_ctf_pointer_type().
Handle type tags in gen_ctf_typedef() too, mirroring the pointer handling,
so that a BTF_KIND_TYPE_TAG record is inserted into the chain between the
typedef and its underlying type:
BTF_KIND_TYPEDEF 'uint_t' -> BTF_KIND_TYPE_TAG 'td_tag'
-> BTF_KIND_INT 'unsigned int'
There are two places a tag can be attached to a typedef, both handled here:
- A tag supplied in the typedef definition annotates the underlying type,
so the DW_AT_GNU_annotation is found on the DW_AT_type target of the
typedef DIE (innermost tags). A pointer target is skipped, as pointers
already consume their own type tags in gen_ctf_pointer_type(), otherwise
the tag would be emitted twice.
- A tag supplied on a use of an existing typedef is attached to a cloned
typedef DIE (see modified_type_die), so the annotation is found on the
typedef DIE itself (outermost tags).
The new code is guarded by btf_debuginfo_p (), so pure CTF output is
unchanged.
PR debug/125888
gcc/ChangeLog:
* dwarf2ctf.cc (gen_ctf_typedef): Emit BTF type tags attached to
the typedef's underlying type or to the typedef DIE itself.
* doc/extend.texi (btf_type_tag): Document that BTF type tags are
now emitted for typedefs in addition to pointer types.
gcc/testsuite/ChangeLog:
* gcc.dg/debug/btf/btf-type-tag-5.c: New test.
* gcc.dg/debug/btf/btf-type-tag-6.c: New test.
* gcc.dg/debug/btf/btf-type-tag-7.c: New test.
Signed-off-by: Vineet Gupta <[email protected]>
---
gcc/doc/extend.texi | 6 +--
gcc/dwarf2ctf.cc | 29 ++++++++++++++
.../gcc.dg/debug/btf/btf-type-tag-5.c | 39 +++++++++++++++++++
.../gcc.dg/debug/btf/btf-type-tag-6.c | 20 ++++++++++
.../gcc.dg/debug/btf/btf-type-tag-7.c | 29 ++++++++++++++
5 files changed, 120 insertions(+), 3 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-5.c
create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-6.c
create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-7.c
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 2e8ec8a0af2c..dec09f599ced 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -2344,9 +2344,9 @@ when compiled with @option{-gbtf} results in an additional
associating the string @samp{__user} with the normal @code{BTF_KIND_PTR}
record for the pointer-to-integer type used in the declaration.
-Note that the BTF format currently only has a representation for type
-tags associated with pointer types. Type tags on non-pointer types
-may be silently skipped when generating BTF.
+Note that when generating BTF, type tags are currently only emitted for
+type tags associated with pointer types and typedefs. Type tags on
+other types may be silently skipped when generating BTF.
@atindex @code{cleanup}
@cindex cleanup functions
diff --git a/gcc/dwarf2ctf.cc b/gcc/dwarf2ctf.cc
index b9f9e1deeff4..629a48be7ebb 100644
--- a/gcc/dwarf2ctf.cc
+++ b/gcc/dwarf2ctf.cc
@@ -476,6 +476,35 @@ gen_ctf_typedef (ctf_container_ref ctfc, dw_die_ref tdef)
dtd = gen_ctf_type (ctfc, tdef_type);
+ /* Handle BTF type tags. Type tags may be attached to a typedef in two
+ ways, both of which insert type tag records into the chain between the
+ typedef and its underlying type:
+ - A btf_type_tag supplied in the typedef definition annotates the
+ underlying type, so the DW_AT_GNU_annotation is found on the DW_AT_type
+ target of the typedef DIE. These tags are innermost (closest to the
+ underlying type). A pointer target is skipped here, as pointers
+ consume their own type tags in gen_ctf_pointer_type.
+ - A btf_type_tag supplied on a use of an existing typedef is attached to
+ a cloned typedef DIE (see modified_type_die), so the annotation is
+ found on the typedef DIE itself. These tags are outermost (closest to
+ the typedef). */
+ if (btf_debuginfo_p ())
+ {
+ if (tdef_type
+ && dw_get_die_tag (tdef_type) != DW_TAG_pointer_type)
+ {
+ dw_die_ref def_annot = get_AT_ref (tdef_type, DW_AT_GNU_annotation);
+ ctf_dtdef_ref tag_dtd = handle_ctf_type_tags (ctfc, def_annot, dtd);
+ if (tag_dtd)
+ dtd = tag_dtd;
+ }
+
+ dw_die_ref use_annot = get_AT_ref (tdef, DW_AT_GNU_annotation);
+ ctf_dtdef_ref tag_dtd = handle_ctf_type_tags (ctfc, use_annot, dtd);
+ if (tag_dtd)
+ dtd = tag_dtd;
+ }
+
/* Type de-duplication.
This is necessary because the ctf for the typedef may have been already
added due to the gen_ctf_type call above. */
diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-5.c
b/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-5.c
new file mode 100644
index 000000000000..f121db2a42d5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-5.c
@@ -0,0 +1,39 @@
+/* Test generation of BTF type tags applied to typedefs of non-pointer types.
+
+ Unlike btf-type-tag-3.c, where the type tags reach the typedef via a
pointer,
+ here the tags annotate the underlying (non-pointer) type directly, or are
+ applied to a use of an existing typedef. In both cases a BTF_KIND_TYPE_TAG
+ record is inserted into the chain between the typedef and its underlying
+ type. */
+
+/* { dg-do compile } */
+/* { dg-options "-O0 -gbtf -dA" } */
+
+#define __tag1 __attribute__((btf_type_tag("1")))
+#define __tag2 __attribute__((btf_type_tag("2")))
+
+/* Single type tag in the typedef definition.
+ var("a") -> typedef("td1") -> type_tag("1") -> int */
+typedef int __tag1 td1;
+td1 a;
+
+/* Multiple type tags in the typedef definition.
+ var("b") -> typedef("td2") -> type_tag("2") -> type_tag("1") -> int */
+typedef int __tag1 __tag2 td2;
+td2 b;
+
+/* Type tag applied to a use of an existing (untagged) typedef.
+ var("c") -> typedef("base") -> type_tag("1") -> int */
+typedef int base;
+base __tag1 c;
+
+/* { dg-final { scan-assembler-times " BTF_KIND_VAR
'a'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPEDEF 'td1'\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPEDEF
'td1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG '1'\\)" 1 } } */
+
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPEDEF
'td2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG '2'\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG
'2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG '1'\\)" 1 } } */
+
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPEDEF
'base'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG '1'\\)" 1 } } */
+
+/* In total there should be three TYPE_TAG '1' chains feeding an int. */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG
'1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_INT 'int'\\)" 3 } } */
diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-6.c
b/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-6.c
new file mode 100644
index 000000000000..73af0ead4dba
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-6.c
@@ -0,0 +1,20 @@
+/* Test generation of BTF type tags applied to a typedef of a struct type.
+
+ When a btf_type_tag is supplied in the definition of a typedef whose
+ underlying type is a struct, the attribute is recorded on the struct type,
+ i.e. on the DW_AT_type target of the typedef DIE. A BTF_KIND_TYPE_TAG
+ record is therefore inserted into the chain between the typedef and the
+ struct:
+ var("s") -> typedef("S_t") -> type_tag("t1") -> struct("S") */
+
+/* { dg-do compile } */
+/* { dg-options "-O0 -gbtf -dA" } */
+
+#define __tag1 __attribute__((btf_type_tag("t1")))
+
+typedef struct S { int x; } __tag1 S_t;
+S_t s;
+
+/* { dg-final { scan-assembler-times " BTF_KIND_VAR
's'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPEDEF 'S_t'\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPEDEF
'S_t'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG 't1'\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG
't1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_STRUCT 'S'\\)" 1 } } */
diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-7.c
b/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-7.c
new file mode 100644
index 000000000000..5fc1a61407be
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-7.c
@@ -0,0 +1,29 @@
+/* Test generation of BTF type tags on a function whose return type and
+ arguments are tagged typedefs. PR/125888.
+
+ foo: FUNC_PROTO -> ret typedef("PERCPU_T") -> type_tag("percpu") -> int
+ -> args typedef("CPU_T") -> type_tag("cpu") -> int
*/
+
+/* { dg-do compile } */
+/* { dg-options "-O0 -gbtf -dA" } */
+
+#define __tag1 __attribute__((btf_type_tag("percpu")))
+#define __tag2 __attribute__((btf_type_tag("cpu")))
+
+typedef int __tag1 PERCPU_T;
+typedef int __tag2 CPU_T;
+
+PERCPU_T foo (CPU_T a, CPU_T b)
+{
+ PERCPU_T c = a + b;
+ return c;
+}
+
+/* Return is the tagged typedef PERCPU_T. */
+/* { dg-final { scan-assembler-times " BTF_KIND_FUNC_PROTO
''(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPEDEF 'PERCPU_T'\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPEDEF
'PERCPU_T'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG 'percpu'\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG
'percpu'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_INT 'int'\\)" 1 } } */
+
+/* Arguments are the tagged typedef CPU_T. */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPEDEF
'CPU_T'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG 'cpu'\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG
'cpu'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_INT 'int'\\)" 1 } } */
--
2.54.0