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

Reply via email to