On 10/13/25 00:16, Richard Biener wrote:
> On Sat, Oct 11, 2025 at 3:21 AM David Faust <[email protected]> wrote:
>>
>> The check in gen_btf_tag_dies which asserted that if the target DIE
>> already had an annotation then it must be the same as the one we are
>> attempting to add was too strict.  It is valid for multiple declarations
>> of the same object to appear with different decl_tags, in which case the
>> tags are accumulated in the DECL_ATTRIBUTES, but the existing tag may
>> not be the same as the one being added.  This was not handled correctly
>> and led to the ICE reported in the PR.
>>
>> The more accurate requirement for consistency is that if there is an
>> existing chain of annotations, then it is a sub-chain of the one we are
>> adding in the current pass.  This patch fixes gen_btf_tag_dies to use
>> the more accurate check and properly handle the case in the PR.
>>
>> Bootstrapped and tested on x86_64-linux-gnu.
>>
>> OK for trunk?
>> Thanks
>>
>>         PR debug/122248
>>
>> gcc/
>>
>>         * dwarf2out.cc (gen_btf_tag_dies): Handle repeated declarations
>>         of the same object with different decl_tags and improve accuracy
>>         of the consistency check under flag_checking.
>>
>> gcc/testsuite/
>>
>>         * gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-4.c: New.
>>         * gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-5.c: New.
>>         * gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-6.c: New.
>> ---
>>  gcc/dwarf2out.cc                              | 27 +++++++++++---
>>  .../debug/dwarf2/dwarf-btf-decl-tag-4.c       | 28 +++++++++++++++
>>  .../debug/dwarf2/dwarf-btf-decl-tag-5.c       | 35 +++++++++++++++++++
>>  .../debug/dwarf2/dwarf-btf-decl-tag-6.c       | 24 +++++++++++++
>>  4 files changed, 109 insertions(+), 5 deletions(-)
>>  create mode 100644 gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-4.c
>>  create mode 100644 gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-5.c
>>  create mode 100644 gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-6.c
>>
>> diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc
>> index a817c69c95a..8fe6e3321e1 100644
>> --- a/gcc/dwarf2out.cc
>> +++ b/gcc/dwarf2out.cc
>> @@ -13843,13 +13843,30 @@ gen_btf_tag_dies (tree attr, dw_die_ref 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.  */
>> +        There may be an existing annotation chain, as in the case of global
>> +        decls which may can processed (and declared) multiple times.
>> +        Each time a global decl is processed it may have additional
>> +        decl_tags, but the set should never shrink.  */
>>        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);
>> +       {
>> +         if (flag_checking)
>> +           {
>> +             /* If there is an existing annotation chain, then it must be a
>> +                sub-chain of this one, i.e. its head must be somewhere in 
>> the
>> +                chain from tag_die.  Otherwise we may have a bug.  */
> 
> A bug in the DWARF implementation or in the users use of attributes?
> The latter should not be diagnosed with an assert.

A bug in the DWARF implementation.

It would mean for example that we have somehow processed two distinct types
like

  int __attribute__((btf_type_tag ("A"))) foo;
  int __attribute__((btf_type_tag ("B"))) bar;

And tried to share the base int DIE between them, despite having
incompatible sets of type_tag.  Cases like this should always result
in two distinct type DIEs.  This happens naturally for types, since
we get two distinct integer type TREE nodes each with the appropriate
TYPE_ATTRIBUTES, and each integer type is processed once.

Catching such a bug in the implementation was the intent of the
gcc_checking_assert (existing == tag_die), but that didn't properly
account for cases with declaration tags like:

  int foo __attribute__((btf_decl_tag ("tag1")));
  int foo __attribute__((btf_decl_tag ("tag2")));

In this case, the decl 'foo' is processed once each time it appears.

First, DECL_ATTRIBUTES ('foo') contains only tag1, and we annotate
the DIE for it with an AT_GNU_annotation pointing to DIE for tag1.

The second time, DECL_ATTRIBUTES ('foo') is the list (tag2, tag1).
So 'existing' is the DIE for tag1, and 'tag_die' is the DIE for tag2,
which then points via AT_GNU_annotation to the DIE for tag1.

This is correct, but the simple (existing == tag_die) was too strict.
Instead we should look for existing in tag_die's chain.  If it is not
there at all, that would indicate a bug in the implementation, since
tag1 is still present in DECL_ATTRIBUTES for foo.

> 
>> +             dw_die_ref d = tag_die;
>> +             while (d && d != existing)
>> +               d = get_AT_ref (die, DW_AT_GNU_annotation);
>> +
>> +             gcc_assert (d);
>> +           }
>> +
>> +         /* Remove the existing annotation and replace it with the new.  */
>> +         remove_AT (die, DW_AT_GNU_annotation);
>> +       }
>> +
>> +      add_AT_die_ref (die, DW_AT_GNU_annotation, tag_die);
>>      }
>>
>>    return tag_die;
>> diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-4.c 
>> b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-4.c
>> new file mode 100644
>> index 00000000000..6fdcdc6e864
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-4.c
>> @@ -0,0 +1,28 @@
>> +/* Test DWARF generation for decl_tags on global decls appearing multiple
>> +   times with different decl_tags.  PR122248.  */
>> +/* { dg-do compile } */
>> +/* { dg-options "-gdwarf -dA" } */
>> +
>> +#define __tag1 __attribute__((btf_decl_tag ("tag1")))
>> +#define __tag2 __attribute__((btf_decl_tag ("tag2")))
>> +#define __tag3 __attribute__((btf_decl_tag ("tag3")))
>> +#define __tag4 __attribute__((btf_decl_tag ("tag4")))
>> +
>> +int foo __tag1;
>> +int foo __tag2;
>> +
>> +/* Result: foo has __tag1 and __tag2.  */
>> +
>> +int bar __tag3;
>> +int bar;
>> +
>> +/* Result: bar has __tag3.  */
>> +
>> +int baz;
>> +int baz __tag4;
>> +
>> +/* Result: baz has __tag4.  */
>> +
>> +/* { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) 
>> DW_TAG_GNU_annotation" 4 } } */
>> +/* { dg-final { scan-assembler-times " DW_AT_GNU_annotation" 4 } } */
>> +
>> diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-5.c 
>> b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-5.c
>> new file mode 100644
>> index 00000000000..c7cb60ca986
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-5.c
>> @@ -0,0 +1,35 @@
>> +/* Test DWARF generation for decl_tags on global decls appearing multiple
>> +   times with different decl_tags.  PR122248.  */
>> +/* { dg-do compile } */
>> +/* { dg-options "-gdwarf -dA" } */
>> +
>> +#define __tag1 __attribute__((btf_decl_tag ("tag1")))
>> +#define __tag2 __attribute__((btf_decl_tag ("tag2")))
>> +#define __tag3 __attribute__((btf_decl_tag ("tag3")))
>> +
>> +struct S
>> +{
>> +  int x;
>> +  char c;
>> +};
>> +
>> +extern struct S foo __tag1;
>> +struct S foo __tag2;
>> +
>> +/* Result: non-completing variable DIE for 'foo' has tag1, and the
>> +   completing DIE (with AT_specification) for 'foo' has tag2 -> tag1.  */
>> +
>> +extern int a __tag3;
>> +int a;
>> +
>> +/* Result: non-completing variable DIE for a has tag3, and the
>> +   completing DIE (with AT_specification) for 'a' also refers to tag3.  */
>> +
>> +/* { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) 
>> DW_TAG_GNU_annotation" 3 } } */
>> +
>> +/* 5 AT_GNU annotations:
>> +   - foo -> tag1
>> +   - foo -> tag2 -> tag1
>> +   - a -> tag3
>> +   - a -> tag3 */
>> +/* { dg-final { scan-assembler-times " DW_AT_GNU_annotation" 5 } } */
>> diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-6.c 
>> b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-6.c
>> new file mode 100644
>> index 00000000000..dd89d1142b9
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-btf-decl-tag-6.c
>> @@ -0,0 +1,24 @@
>> +/* Test DWARF generation for decl_tags on global decls appearing multiple
>> +   times with different decl_tags.  PR122248.  */
>> +/* { dg-do compile } */
>> +/* { dg-options "-gdwarf -dA" } */
>> +
>> +#define __tag1 __attribute__((btf_decl_tag ("tag1")))
>> +#define __tag2 __attribute__((btf_decl_tag ("tag2")))
>> +#define __tag3 __attribute__((btf_decl_tag ("tag3")))
>> +
>> +__tag1
>> +extern int
>> +do_thing (int);
>> +
>> +__tag2
>> +__tag3
>> +int
>> +do_thing (int x)
>> +{
>> +  return x * x;
>> +}
>> +
>> +/* Result: do_thing has all 3 tags.  */
>> +/* { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) 
>> DW_TAG_GNU_annotation" 3 } } */
>> +/* { dg-final { scan-assembler-times " DW_AT_GNU_annotation" 3 } } */
>> --
>> 2.51.0
>>

Reply via email to