> "Jose E. Marchesi" <[email protected]> writes:
>
>> ping
>
> richi already approved it some time ago:
> https://inbox.sourceware.org/gcc-patches/[email protected]/
Oh missed that. Thanks for pointing that out.
Doing the backport then.
>
>>
>>> This BPF related patch involved dwarf2out.
>>> Is it OK for GCC 16?
>>>
>>> ---
>>>
>>> typedef chain traversal could sometimes skip an intermediate type.
>>> This could happen when two DIEs have a common underlying type but diverge
>>> due to presence of additional attribute in one case and a qualifier in
>>> other.
>>> In the example from testcase, variable "perm" typechain misses interim u16.
>>>
>>> typedef unsigned short __u16;
>>> typedef __u16 u16;
>>> __attribute__((btf_type_tag(""))) u16 a;
>>> const u16 perm;
>>>
>>> generates
>>>
>>> .uleb128 0x1 # (DIE (0x66) DW_TAG_variable)
>>> .long .LASF3 # DW_AT_name: "perm"
>>> # DW_AT_decl_file (1, pr125421.c)
>>> .byte 0xa # DW_AT_decl_line
>>> .byte 0xb # DW_AT_decl_column
>>> .long 0x2f # DW_AT_type
>>>
>>> .uleb128 0x4 # (DIE (0x2f) DW_TAG_const_type)
>>> .long 0x23 # DW_AT_type <-- BUG
>>>
>>> .uleb128 0x3 # (DIE (0x23) DW_TAG_typedef)
>>> .long .LASF5 # DW_AT_name: "__u16"
>>> .byte 0x1 # DW_AT_decl_file (pr125421.c)
>>> .byte 0x7 # DW_AT_decl_line
>>> .byte 0xf # DW_AT_decl_column
>>> .long 0x34 # DW_AT_type
>>>
>>> .uleb128 0x5 # (DIE (0x34) DW_TAG_base_type)
>>> .byte 0x2 # DW_AT_byte_size
>>> .byte 0x5 # DW_AT_encoding
>>> .long .LASF6 # DW_AT_name: "short int"
>>>
>>> What makes this issue worse is depending on the order in which the types
>>> are specified in source, and processed, the problem may or maynot show up.
>>> So in the test code above if lines 3 and 4 are swppaed, "perm" gets the
>>> missing type u16 as expected.
>>>
>>> The issue is in modified_type_die (), get_qualified_type (type) returned
>>> pointer may not be identical to dtype: TREE_TYPE (TYPE_NAME
>>> (qualified_type))
>>> while having the same underlying base type. And due to the failed
>>> pointer identity test, subsequent usage of DECL_ORIGINAL_TYPE () for
>>> recursive
>>> chain processing can peel away the needed type.
>>>
>>> The implications are for a multi CU build, structurally similar but
>>> non identical variants of types (due to an embedded member getting a
>>> different chained typdef) can be generated and accumulate at link time
>>> in the final .debug_info.
>>>
>>> This would be OK / unnoticed for usual dwarf debugging purposes.
>>> However in BFP workflow: kernel binary linking invokes pahole to process
>>> the dwarf and dedup it for btf generation (gcc can emit btf directly but
>>> thats not been done currently for other reasons). The slightly different
>>> variations of same structure due to thi issue cause combinatiorial explosion
>>> in pahole dedup processing trying to match and failing repeatedly in what
>>> seems like infinite recursion. The problem showed up and was excerbated
>>> when trying to enable attr btf_type_tag in kernel with gcc for the first
>>> time as that is the key ingredient to trigger the latent issue.
>>>
>>> Fix is to handle qualified_type != dtype as if they were identical when
>>> they are different variant nodes of the same underlying typedef.
>>>
>>> Bootstrapped and regtested on x86 and aarch64.
>>>
>>> PR debug/125421
>>>
>>> gcc/ChangeLog:
>>>
>>> * dwarf2out.cc (modified_type_die): Handle qualified_type being
>>> a variant of dtype as if they were identical to avoid peeling a
>>> typdef.
>>> For named types, use dentry unconditionally as that is valid for
>>> both cases of qualified_type == and != dentry.
>>>
>>> gcc/testsuite/ChangeLog:
>>>
>>> * gcc.dg/debug/dwarf2/pr125421.c: New Test.
>>>
>>> Signed-off-by: Vineet Gupta <[email protected]>
>>> (cherry picked from commit 3e2885588fe0e5273a50c471d41c61ee9aefc269)
>>> ---
>>> gcc/dwarf2out.cc | 15 ++++++++++++---
>>> gcc/testsuite/gcc.dg/debug/dwarf2/pr125421.c | 18 ++++++++++++++++++
>>> 2 files changed, 30 insertions(+), 3 deletions(-)
>>> create mode 100644 gcc/testsuite/gcc.dg/debug/dwarf2/pr125421.c
>>>
>>> diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc
>>> index bf342e468bf..9d6ca06067f 100644
>>> --- a/gcc/dwarf2out.cc
>>> +++ b/gcc/dwarf2out.cc
>>> @@ -13997,7 +13997,16 @@ modified_type_die (tree type, int cv_quals, tree
>>> type_attrs, bool reverse,
>>> tree dtype = TREE_TYPE (name);
>>>
>>> /* Skip the typedef for base types with DW_AT_endianity, no big
>>> deal. */
>>> - if (qualified_type == dtype && !reverse_type)
>>> + if (!reverse_type
>>> + && (qualified_type == dtype
>>> + /* Pointer identity check above might fail when qualified_type
>>> + is a different variant node of the same typedef yet requires
>>> + the same handling as if they matched (see PR/125421).
>>> + Skip this when btf_type_tag attributes are present, as those
>>> + need to be handled in the else branch below. */
>>> + || (TYPE_NAME (qualified_type) == name
>>> + && TYPE_QUALS (qualified_type) == TYPE_QUALS (dtype)
>>> + && !lookup_attribute ("btf_type_tag", type_attrs))))
>>> {
>>> tree origin = decl_ultimate_origin (name);
>>>
>>> @@ -14009,8 +14018,8 @@ modified_type_die (tree type, int cv_quals, tree
>>> type_attrs, bool reverse,
>>> reverse, context_die);
>>>
>>> /* For a named type, use the typedef. */
>>> - gen_type_die (qualified_type, context_die);
>>> - return lookup_type_die (qualified_type);
>>> + gen_type_die (dtype, context_die);
>>> + return lookup_type_die (dtype);
>>> }
>>> else
>>> {
>>> diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/pr125421.c
>>> b/gcc/testsuite/gcc.dg/debug/dwarf2/pr125421.c
>>> new file mode 100644
>>> index 00000000000..810afeae739
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/pr125421.c
>>> @@ -0,0 +1,18 @@
>>> +/* Verify the typedef chains are preserved.
>>> + DW_TAG_const_type for "const u16" chains to u16 typedef and doesnot
>>> + skip to underlying __u16 typedef */
>>> +
>>> +/* { dg-do compile } */
>>> +/* { dg-options "-gdwarf -dA" } */
>>> +
>>> +typedef short __u16;
>>> +typedef __u16 u16;
>>> +__attribute__((btf_type_tag(""))) u16 __softirq_pending;
>>> +const u16 perm;
>>> +
>>> +/* The exact failing pattern is hard to encode with TCL regex machinery,
>>> + so resort to an indirect way: in the buggy output, const_type points
>>> + directly to __u16, and only one u16 typedef DIE is emitted (for the
>>> + btf_type_tag use). In the fixed output, const_type points to a u16
>>> + typedef, creating a second u16 typedef DIE.
>>> +/* { dg-final { scan-assembler-times "(DW_AT_name:
>>> \"u16\"|\"u16..\"\[^\\r\\n\]*DW_AT_name)" 2 } } */