https://gcc.gnu.org/bugzilla/show_bug.cgi?id=125421
Bug ID: 125421
Summary: dwarf typechain handling not consistent
Product: gcc
Version: 16.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: debug
Assignee: vineetg at gcc dot gnu.org
Reporter: vineetg at gcc dot gnu.org
CC: dfaust at gcc dot gnu.org, jemarch at gcc dot gnu.org
Target Milestone: ---
gcc 16 contains David's awesome work [1] to allow dwarf/btf to record
__attribute__((btf_type_tag("...")) as DW_{AT,TAG}_GNU_annotation (which are
semantically different from DW_{AT,TAG}_LLVM_annotation).
I was trying to enable this in the bpf ecosystem [2][3] and ran into an issue
with [3]
[1] https://gcc.gnu.org/pipermail/gcc-patches/2025-September/696239.html
[2] Linux kernel build currently only supports LLVM's variant of tag/attr
[3] pahole currently doesn't support GNU tag/attr
pahole when trying to parse .debug_info of an attr enabled vmlinux was getting
into what seemed like infinte recursion but was actually combinatorial
explosion. The dedup logic kept traversing nested structs only to discover a
mismatch at the end and fail. The root cause was slightly different variations
of a typechain because in some CUs dwarf generation was skipping over some of
the intermediate types.
e.g.
typedef __u16 u16;
struct kernel_param {
const char *name;
struct module *mod;
const struct kernel_param_ops *ops;
const u16 perm;
s8 level;
u8 flags;
union {
void *arg;
const struct kparam_string *str;
const struct kparam_array *arr;
};
};
was leading to
Canon (CU 1): kernel_param.perm -> CONST -> TYPEDEF u16 -> unsigned short
Cand (CU 2): kernel_param.perm -> CONST -> TYPEDEF __u16 -> unsigned short
Here's a reproducer which shows the problem
```
typedef short __u16;
typedef __u16 u16;
//struct kernel_param *qf_owner;
__attribute__((btf_type_tag(""))) u16 __softirq_pending;
const u16 perm;
```
gcc -Os -g -dA
Problem is for "perm" u16 is skipped and it goes to __u16
```
.long .LASF3 # DW_AT_name: "perm"
# DW_AT_decl_file (1, do_mounts_rd-red.i)
.byte 0x5 # 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) <-- BUG
.long .LASF5 # DW_AT_name: "__u16"
.byte 0x1 # DW_AT_decl_file (do_mounts_rd-red.i)
.byte 0x1 # DW_AT_decl_line
.byte 0xf # DW_AT_decl_column
.long 0x34 # DW_AT_type
```
clang generates the right traversal as seen here:
https://godbolt.org/z/Gbb57Ms1K