https://gcc.gnu.org/g:d5f30b7d5285679805796461beeb2f7ce4b25c44
commit r16-4753-gd5f30b7d5285679805796461beeb2f7ce4b25c44 Author: David Faust <[email protected]> Date: Wed Oct 29 15:21:16 2025 -0700 btf: do not prune at typedefs The existing BTF pruning logic meant that an anonymous struct or union type hidden behind a typedef, such as in the common construct: typedef struct { ... } my_struct_type; could be pruned if 'my_struct_type' was only ever referenced via pointer members in other structs/unions types used in the program. The result of pruning is to skip emitting full type information for a struct or union type by replacing it with a BTF_KIND_FWD, indicating that it exists but its definition is omitted. Any types used only by pruned types are fully omitted from the generated BTF. In cases like this where the struct/union type is anonymous, the result is an anonymous BTF_KIND_FWD, which is useless. The presence of such a type record rightly causes complaints from BTF loaders. Worse, since the TYPEDEF for 'my_struct_type' itself may _not_ be pruned, its type information will be incomplete. Change the BTF pruner so that we never consider pruning at a typedef, and always either keep or discard both the type and the typedef. gcc/ * btfout.cc (btf_add_used_type_1): Do not consider creating fixups at typedefs. gcc/testsuite/ * gcc.dg/debug/btf/btf-prune-4.c: New. Diff: --- gcc/btfout.cc | 3 +- gcc/testsuite/gcc.dg/debug/btf/btf-prune-4.c | 61 ++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/gcc/btfout.cc b/gcc/btfout.cc index 5a210cd51e6c..eb794ff86944 100644 --- a/gcc/btfout.cc +++ b/gcc/btfout.cc @@ -1138,7 +1138,8 @@ btf_add_used_type_1 (ctf_container_ref ctfc, ctf_dtdef_ref dtd, /* Try to avoid chasing pointers to struct/union types if the underlying type isn't used. */ - if (check_ptr && seen_ptr && create_fixups) + if (check_ptr && seen_ptr && create_fixups + && kind != BTF_KIND_TYPEDEF) { ctf_dtdef_ref ref = dtd->ref_type; uint32_t ref_kind = btf_dtd_kind (ref); diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-prune-4.c b/gcc/testsuite/gcc.dg/debug/btf/btf-prune-4.c new file mode 100644 index 000000000000..3f1955938128 --- /dev/null +++ b/gcc/testsuite/gcc.dg/debug/btf/btf-prune-4.c @@ -0,0 +1,61 @@ +/* Test that -gprune-btf does not prune at typedefs. */ + +/* { dg-do compile } */ +/* { dg-options "-gbtf -gprune-btf -dA" } */ + +/* We must have the full definitions of td1 and td3. Neither are pruned. + td2 will be skipped entirely, only because the only reference to + it is through struct inner, which is pruned because inner itself + is only used as a pointer member. + + In general, we must never get an anonymous FWD; the only FWD in this + case will be for 'inner' */ + +/* Exactly 1 FWD for inner and no anonymous FWD. */ +/* { dg-final { scan-assembler-times "TYPE \[0-9\]+ BTF_KIND_FWD" 1 } } */ +/* { dg-final { scan-assembler-not "TYPE \[0-9\]+ BTF_KIND_FWD ''" } } */ +/* { dg-final { scan-assembler " BTF_KIND_FWD 'inner'" } } */ + +/* One anonymous struct for td1 and one anonymous union for td3. */ +/* { dg-final { scan-assembler-times "TYPE \[0-9\]+ BTF_KIND_STRUCT ''" 1 } } */ +/* { dg-final { scan-assembler-times "TYPE \[0-9\]+ BTF_KIND_UNION ''" 1 } } */ + +/* The two remaining typedefs. */ +/* { dg-final { scan-assembler " BTF_KIND_TYPEDEF 'td1'" } } */ +/* { dg-final { scan-assembler " BTF_KIND_TYPEDEF 'td3'" } } */ + +typedef struct { + int x; + char c; +} td1; + +typedef struct { + long l; + char b[4]; +} td2; + +typedef union { + long l; + unsigned short s[2]; +} td3; + +struct inner { + char a; + td2 *ptd; + long z; +}; + +struct A { + td1 *pt; + struct inner *in; + unsigned long l[4]; +}; + +struct A foo; + +struct B { + int x; + td3 **ppptd3; +}; + +struct B bar;
