On 10/13/25 09:28, David Faust wrote:
>
>
> 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.
Hmm, Ping. Is this patch OK?
Or would you rather I remove the if (flag_checking) block and its assert?
>
> 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
>>>
>