On 10/12/25 22:53, Jose E. Marchesi 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.
I just noticed a typo in the comment here: "may be" or "can be" became
"may can". Fixed locally.
>> + 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. */
>> + 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);
>
> tag_die here contains the accummulated tags?
Yes, it is the result of building the complete chain of tags
on the given object from TYPE_ATTRIBUTES or DECL_ATTRIBUTES.
If an object is re-declared with different decl_tags, they
accumulate in DECL_ATTRIBUTES.
so e.g. if __tag1 and __tag2 are btf_decl_tags, then
struct S { ... };
struct S foo __tag1;
struct S foo __tag2;
The decl 'foo' is processed twice.
First, DECL_ATTRIBUTES ('foo') is the list (__tag1).
And tag_die is the lone DIE for tag1.
Second, DECL_ATTRIBUTES ('foo') is (__tag2, __tag1).
Now tag_die is the chain of two DIEs: tag2 -> tag1.
The work of building the chain as necessary is already done
by the existing implementation, so we can just swap existing
with the new head-of-chain.
>
>> }
>>
>> 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 } } */