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

Reply via email to