All of lore.kernel.org
 help / color / mirror / Atom feed
* pahole treats embedded structures a holes
@ 2026-05-28  5:11 Christoph Hellwig
  2026-05-28 13:39 ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 7+ messages in thread
From: Christoph Hellwig @ 2026-05-28  5:11 UTC (permalink / raw)
  To: dwarves

[-- Attachment #1: Type: text/plain, Size: 969 bytes --]

Hi all,

this is a pretty old bug as far as I can tell, but I finally tried to
track it down and failed.

When running dwarves, both the package in Debian testing and a build of
todays git tree on Debian testing, it treats a lot of C structures
embedded into others as holes instead of having a size for them.  I
think this generally structures defined in other header files and
not the file containing the offending struct.

E.g. if I run pahole on fs/xfs/xfs_buf.o on a current mainline kernel,
the output for struct xfs_buf starts like this:

struct xfs_buf {
        struct rhash_head          b_rhash_head;         /*     0     0 */

        /* XXX 8 bytes hole, try to pack */

        xfs_daddr_t                b_rhash_key;          /*     8     8 */

struct rhash_head is a single pointer, so 8 bytes on x86-64, and
xfs_daddr_t is also a 64-bit type, so both the 0 size and the 8
byte hole are clearly wrong.  The kernel .config is attached in case
it matter.

[-- Attachment #2: config.gz --]
[-- Type: application/x-gzip, Size: 26863 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: pahole treats embedded structures a holes
  2026-05-28  5:11 pahole treats embedded structures a holes Christoph Hellwig
@ 2026-05-28 13:39 ` Arnaldo Carvalho de Melo
  2026-05-28 13:58   ` Christoph Hellwig
  0 siblings, 1 reply; 7+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-05-28 13:39 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: dwarves

On Thu, May 28, 2026 at 07:11:52AM +0200, Christoph Hellwig wrote:
> Hi all,
> 
> this is a pretty old bug as far as I can tell, but I finally tried to
> track it down and failed.
> 
> When running dwarves, both the package in Debian testing and a build of
> todays git tree on Debian testing, it treats a lot of C structures
> embedded into others as holes instead of having a size for them.  I
> think this generally structures defined in other header files and
> not the file containing the offending struct.
> 
> E.g. if I run pahole on fs/xfs/xfs_buf.o on a current mainline kernel,
> the output for struct xfs_buf starts like this:
> 
> struct xfs_buf {
>         struct rhash_head          b_rhash_head;         /*     0     0 */
> 
>         /* XXX 8 bytes hole, try to pack */
> 
>         xfs_daddr_t                b_rhash_key;          /*     8     8 */
> 
> struct rhash_head is a single pointer, so 8 bytes on x86-64, and
> xfs_daddr_t is also a 64-bit type, so both the 0 size and the 8
> byte hole are clearly wrong.  The kernel .config is attached in case
> it matter.

Starting from using the BTF info, that becomes available thru sysfs as
soon as we load the xfs kernel module:

acme@x1:~$ ls -la /sys/kernel/btf/xfs
ls: cannot access '/sys/kernel/btf/xfs': No such file or directory
acme@x1:~$ sudo modprobe xfs
acme@x1:~$ ls -la /sys/kernel/btf/xfs
-r--r--r--. 1 root root 630917 May 28 10:33 /sys/kernel/btf/xfs
acme@x1:~$
acme@x1:~$ pahole --sizes /sys/kernel/btf/xfs | sort -nr -k2 | grep xfs | head 
xfs_mount	4032	8
xfs_dquot_acct	1320	0
xfs_cil_ctx	1240	2
xfsstats	1088	0
__xfsstats	1088	0
xfs_inode	984	2
xfs_quotainfo	552	1
xfs_dquot	536	3
xfs_perag	480	4
xfs_da_state	480	1
acme@x1:~$

Now to the 'xfs_buf' struct:

acme@x1:~$ pahole /sys/kernel/btf/xfs -C xfs_buf | head
struct xfs_buf {
	struct rhash_head          b_rhash_head;         /*     0     8 */
	xfs_daddr_t                b_rhash_key;          /*     8     8 */
	int                        b_length;             /*    16     4 */
	unsigned int               b_hold;               /*    20     4 */
	atomic_t                   b_lru_ref;            /*    24     4 */
	xfs_buf_flags_t            b_flags;              /*    28     4 */
	struct semaphore           b_sema;               /*    32    24 */
	struct list_head           b_lru;                /*    56    16 */
	/* --- cacheline 1 boundary (64 bytes) was 8 bytes ago --- */
acme@x1:~$

Seems ok, expanding it:

acme@x1:~$ pahole -E /sys/kernel/btf/xfs -C xfs_buf | head
struct xfs_buf {
	struct rhash_head {
		struct rhash_head * next;                                                /*     0     8 */
	} b_rhash_head; /*     0     8 */
	/* typedef xfs_daddr_t -> __s64 */ long long int              b_rhash_key;       /*     8     8 */
	int                        b_length;                                             /*    16     4 */
	unsigned int               b_hold;                                               /*    20     4 */
	/* typedef atomic_t */ struct {
		int                counter;                                              /*    24     4 */
	} b_lru_ref; /*    24     4 */
acme@x1:~$

Looks ok and with your description of the struct, a pointer, 8 bytes,
etc.

Now I'll try with a fresh kernel build, with a default fedora kernel
config, will take a while, but having access to a separate .o file from
the kernel build process, with just DWARF info is what we need to get to
the state you're in, that should work, lets see why you're getting the
unsatisfactory results you're getting, maybe we need further info about
compiler versions, etc, but lets see...

- Arnaldo

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: pahole treats embedded structures a holes
  2026-05-28 13:39 ` Arnaldo Carvalho de Melo
@ 2026-05-28 13:58   ` Christoph Hellwig
  2026-05-28 19:48     ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 7+ messages in thread
From: Christoph Hellwig @ 2026-05-28 13:58 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo; +Cc: dwarves

On Thu, May 28, 2026 at 10:39:34AM -0300, Arnaldo Carvalho de Melo wrote:
> > struct rhash_head is a single pointer, so 8 bytes on x86-64, and
> > xfs_daddr_t is also a 64-bit type, so both the 0 size and the 8
> > byte hole are clearly wrong.  The kernel .config is attached in case
> > it matter.
> 
> Starting from using the BTF info, that becomes available thru sysfs as
> soon as we load the xfs kernel module:

This works fine on my installed distro kernel as well.  But this is
for test builds which are only going to run in a VM.  I don't really
care about DWARF vs BTF, but I do care about not having to run the
kernel :)

Note that I'm also seeing this for other code than XFS, e.g. the nvme
driver or block layer code.

> Now I'll try with a fresh kernel build, with a default fedora kernel
> config, will take a while, but having access to a separate .o file from
> the kernel build process, with just DWARF info is what we need to get to
> the state you're in, that should work, lets see why you're getting the
> unsatisfactory results you're getting, maybe we need further info about
> compiler versions, etc, but lets see...

gcc (Debian 15.2.0-17) 15.2.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: pahole treats embedded structures a holes
  2026-05-28 13:58   ` Christoph Hellwig
@ 2026-05-28 19:48     ` Arnaldo Carvalho de Melo
  2026-05-29  4:02       ` Christoph Hellwig
  0 siblings, 1 reply; 7+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-05-28 19:48 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: dwarves

On Thu, May 28, 2026 at 03:58:52PM +0200, Christoph Hellwig wrote:
> On Thu, May 28, 2026 at 10:39:34AM -0300, Arnaldo Carvalho de Melo wrote:
> > > struct rhash_head is a single pointer, so 8 bytes on x86-64, and
> > > xfs_daddr_t is also a 64-bit type, so both the 0 size and the 8
> > > byte hole are clearly wrong.  The kernel .config is attached in case
> > > it matter.

> > Starting from using the BTF info, that becomes available thru sysfs as
> > soon as we load the xfs kernel module:
 
> This works fine on my installed distro kernel as well.  But this is
> for test builds which are only going to run in a VM.  I don't really
> care about DWARF vs BTF, but I do care about not having to run the
> kernel :)

Sure, I was just checking with what I had at hand, before building the
kernel, to see if the problem was there as well.
 
> Note that I'm also seeing this for other code than XFS, e.g. the nvme
> driver or block layer code.
 
> > Now I'll try with a fresh kernel build, with a default fedora kernel
> > config, will take a while, but having access to a separate .o file from
> > the kernel build process, with just DWARF info is what we need to get to
> > the state you're in, that should work, lets see why you're getting the
> > unsatisfactory results you're getting, maybe we need further info about
> > compiler versions, etc, but lets see...
 
> gcc (Debian 15.2.0-17) 15.2.0

acme@number:~$ pahole -C xfs_buf git/build/allmodconfig/fs/xfs/xfs_buf.o  | head
struct xfs_buf {
	struct rhash_head          b_rhash_head;         /*     0     8 */
	xfs_daddr_t                b_rhash_key;          /*     8     8 */
	int                        b_length;             /*    16     4 */

	/* XXX 4 bytes hole, try to pack */

	struct lockref             b_lockref __attribute__((__aligned__(8))); /*    24    80 */
	/* --- cacheline 1 boundary (64 bytes) was 40 bytes ago --- */
	atomic_t                   b_lru_ref __attribute__((__aligned__(4))); /*   104     4 */
acme@number:~$

acme@number:~$ pahole -E -C xfs_buf git/build/allmodconfig/fs/xfs/xfs_buf.o  | head
struct xfs_buf {
	struct rhash_head {
		struct rhash_head * next;                                                /*     0     8 */
	} b_rhash_head; /*     0     8 */
	/* typedef xfs_daddr_t -> __s64 */ long long int              b_rhash_key;       /*     8     8 */
	int                        b_length;                                             /*    16     4 */

	/* XXX 4 bytes hole, try to pack */

	struct lockref {
acme@number:~$

acme@number:~$ readelf -wi git/build/allmodconfig/fs/xfs/xfs_buf.o  | grep -m1 DW_AT_producer
    <e>   DW_AT_producer    : (indirect string, offset: 0x923f): GNU C11 16.1.1 20260515 (Red Hat 16.1.1-2) -march=znver5 -mpopcnt -msse3 -mssse3 -msse4.1 -msse4.2 -mavx2 -mno-fma4 -mno-xop -mfma -mavx512f -mbmi -mbmi2 -maes -mpclmul -mavx512vl -mavx512bw -mavx512dq -mavx512cd -mavx512vbmi -mavx512ifma -mavx512vpopcntdq -mavx512vbmi2 -mgfni -mvpclmulqdq -mavx512vnni -mavx512bitalg -mavx512bf16 -mavx512vp2intersect -madx -mabm -mno-cldemote -mclflushopt -mclwb -mclzero -mcx16 -mno-enqcmd -mf16c -mfsgsbase -mfxsr -mno-hle -msahf -mno-lwp -mlzcnt -mmovbe -mmovdir64b -mmovdiri -mmwaitx -mno-pconfig -mpku -mprfchw -mno-ptwrite -mrdpid -mrdrnd -mrdseed -mno-rtm -mno-serialize -mno-sgx -msha -mshstk -mno-tbm -mno-tsxldtrk -mvaes -mno-waitpkg -mwbnoinvd -mxsave -mxsavec -mxsaveopt -mxsaves -mno-amx-tile -mno-amx-int8 -mno-amx-bf16 -mno-uintr -mno-hreset -mno-kl -mno-widekl -mavxvnni -mno-avx512fp16 -mno-avxifma -mno-avxvnniint8 -mno-avxneconvert -mno-cmpccxadd -mno-amx-fp16 -mprefetchi -mno-raoint -mno-amx-complex -mno-avxvnniint16 -mno-sm3 -mno-sha512 -mno-sm4 -mno-apxf -mno-usermsr -mno-avx10.1 -mno-avx10.2 -mno-amx-avx512 -mno-amx-tf32 -mno-amx-fp8 -mno-movrs -mno-amx-movrs -mno-avx512bmm --param=l1-cache-size=48 --param=l1-cache-line-size=64 --param=l2-cache-size=1024 -mtune=znver5 -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx -mno-sse4a -m64 -mno-80387 -mno-fp-ret-in-387 -mpreferred-stack-boundary=3 -mskip-rax-setup -mno-red-zone -mcmodel=kernel -mstack-protector-guard-reg=gs -mstack-protector-guard-symbol=__ref_stack_chk_guard -mindirect-branch=thunk-extern -mindirect-branch-register -mindirect-branch-cs-prefix -mfunction-return=thunk-extern -mharden-sls=all -mrecord-mcount -mfentry -mtls-dialect=gnu2 -g -O2 -std=gnu11 -p -fshort-wchar -funsigned-char -fno-common -fno-PIE -fno-strict-aliasing -fms-extensions -fcf-protection=branch -falign-jumps=1 -falign-loops=1 -fno-asynchronous-unwind-tables -fno-jump-tables -fpatchable-function-entry=64,64 -fno-delete-null-pointer-checks -fno-allow-store-data-races -fno-reorder-blocks -fno-ipa-cp-clone -fno-partial-inlining -fstack-protector-strong -ftrivial-auto-var-init=pattern -fzero-init-padding-bits=all -fno-stack-clash-protection -fdiagnostics-show-context=2 -fzero-call-used-regs=used-gpr -fno-inline-functions-called-once -fmin-function-alignment=64 -fstrict-flex-arrays=3 -fno-strict-overflow -fstack-check=no -fconserve-stack -fno-builtin-wcslen -fsanitize=kernel-address -fasan-shadow-offset=0xdffffc0000000000 -fsanitize=bounds-strict -fsanitize=shift -fsanitize=integer-divide-by-zero -fsanitize=bool -fsanitize=enum -fsanitize-coverage=trace-pc -fsanitize-coverage=trace-cmp --param=asan-instrumentation-with-call-threshold=10000 --param=asan-stack=1 --param=asan-instrument-allocas=1 --param=asan-globals=1 --param=asan-kernel-mem-intrinsic-prefix=1
acme@number:~$

then, please take a look at this sequence:

acme@number:~$ readelf -wi git/build/allmodconfig/fs/xfs/xfs_buf.o  | grep -w xfs_buf$ -B1 -A12
 <1><15f59>: Abbrev Number: 76 (DW_TAG_structure_type)
    <15f5a>   DW_AT_name        : (indirect string, offset: 0x8a96): xfs_buf
    <15f5e>   DW_AT_byte_size   : 664
    <15f60>   DW_AT_alignment   : 8
    <15f61>   DW_AT_decl_file   : 49
    <15f62>   DW_AT_decl_line   : 138
    <15f63>   DW_AT_decl_column : 8
    <15f64>   DW_AT_sibling     : <0x1610b>
 <2><15f68>: Abbrev Number: 4 (DW_TAG_member)
    <15f69>   DW_AT_name        : (indirect string, offset: 0x4e54): b_rhash_head
    <15f6d>   DW_AT_decl_file   : 49
    <15f6e>   DW_AT_decl_line   : 146
    <15f6f>   DW_AT_decl_column : 20
    <15f70>   DW_AT_type        : <0x5b22>
acme@number:~$

acme@number:~$ readelf -wi git/build/allmodconfig/fs/xfs/xfs_buf.o  | grep '<5b22>' -A12
 <1><5b22>: Abbrev Number: 30 (DW_TAG_structure_type)
    <5b23>   DW_AT_name        : (indirect string, offset: 0x1bb8): rhash_head
    <5b27>   DW_AT_byte_size   : 8
    <5b28>   DW_AT_decl_file   : 160
    <5b29>   DW_AT_decl_line   : 19
    <5b2a>   DW_AT_decl_column : 8
    <5b2b>   DW_AT_sibling     : <0x5b3d>
 <2><5b2f>: Abbrev Number: 4 (DW_TAG_member)
    <5b30>   DW_AT_name        : (indirect string, offset: 0x123e3): next
    <5b34>   DW_AT_decl_file   : 160
    <5b35>   DW_AT_decl_line   : 20
    <5b36>   DW_AT_decl_column : 28
    <5b37>   DW_AT_type        : <0x5b42>
acme@number:~$

iacme@number:~$ readelf -wi git/build/allmodconfig/fs/xfs/xfs_buf.o  | grep '<5b42>' -A4
 <1><5b42>: Abbrev Number: 8 (DW_TAG_pointer_type)
    <5b43>   DW_AT_byte_size   : 8
    <5b43>   DW_AT_type        : <0x5b22>
 <1><5b47>: Abbrev Number: 30 (DW_TAG_structure_type)
    <5b48>   DW_AT_name        : (indirect string, offset: 0x14c84): rhlist_head
acme@number:~$

So everything is in this CU (debug info for the .o file), at least here,
what do you see on your system?

- Arnaldo

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: pahole treats embedded structures a holes
  2026-05-28 19:48     ` Arnaldo Carvalho de Melo
@ 2026-05-29  4:02       ` Christoph Hellwig
  2026-05-29 19:28         ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 7+ messages in thread
From: Christoph Hellwig @ 2026-05-29  4:02 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo; +Cc: dwarves

On Thu, May 28, 2026 at 04:48:44PM -0300, Arnaldo Carvalho de Melo wrote:
> acme@number:~$ readelf -wi git/build/allmodconfig/fs/xfs/xfs_buf.o  | grep -m1 DW_AT_producer

hch@brick:~/work/xfs$ readelf -wi fs/xfs/xfs_buf.o  | grep -m1 DW_AT_producer
    <d>   DW_AT_producer    : (indirect string, offset: 0x6012): GNU C11 15.2.0 -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx -mno-sse4a -m64 -mno-80387 -mno-fp-ret-in-387 -mpreferred-stack-boundary=3 -mskip-rax-setup -march=x86-64 -mtune=generic -mno-red-zone -mcmodel=kernel -mstack-protector-guard-reg=gs -mstack-protector-guard-symbol=__ref_stack_chk_guard -mindirect-branch=thunk-extern -mindirect-branch-register -mindirect-branch-cs-prefix -mfunction-return=thunk-extern -g -gdwarf-5 -O2 -std=gnu11 -fshort-wchar -funsigned-char -fno-common -fno-PIE -fno-strict-aliasing -fms-extensions -fcf-protection=branch -falign-jumps=1 -falign-loops=1 -fno-asynchronous-unwind-tables -fno-jump-tables -fpatchable-function-entry=16,16 -fno-delete-null-pointer-checks -fno-allow-store-data-races -fstack-protector-strong -fomit-frame-pointer -fzero-init-padding-bits=all -fno-stack-clash-protection -fmin-function-alignment=16 -fstrict-flex-arrays=3 -fno-strict-overflow -fstack-check=no -fconserve-stack -fno-builtin-wcslen -fno-var-tracking -femit-struct-debug-baseonly



> then, please take a look at this sequence:
> 
> acme@number:~$ readelf -wi git/build/allmodconfig/fs/xfs/xfs_buf.o  | grep -w xfs_buf$ -B1 -A12

hch@brick:~/work/xfs$ readelf -wi fs/xfs/xfs_buf.o  | grep -w xfs_buf$ -B1 -A12
 <1><f1c>: Abbrev Number: 93 (DW_TAG_structure_type)
    <f1d>   DW_AT_name        : (indirect string, offset: 0x3358): xfs_buf
    <f21>   DW_AT_byte_size   : 344
    <f23>   DW_AT_alignment   : 8
    <f23>   DW_AT_decl_file   : 46
    <f23>   DW_AT_decl_line   : 138
    <f24>   DW_AT_decl_column : 8
    <f24>   DW_AT_sibling     : <0x10a2>
 <2><f28>: Abbrev Number: 39 (DW_TAG_member)
    <f29>   DW_AT_name        : (indirect string, offset: 0x5e80): b_rhash_head
    <f2d>   DW_AT_decl_file   : 46
    <f2d>   DW_AT_decl_line   : 146
    <f2e>   DW_AT_decl_column : 20
    <f2f>   DW_AT_type        : <0x9c8>


> acme@number:~$ readelf -wi git/build/allmodconfig/fs/xfs/xfs_buf.o  | grep '<5b22>' -A12


hch@brick:~/work/xfs$ readelf -wi fs/xfs/xfs_buf.o  | grep '<0x9c8>' -A12
    <9ce>   DW_AT_type        : <0x9c8>
 <1><9d2>: Abbrev Number: 29 (DW_TAG_structure_type)
    <9d3>   DW_AT_name        : (indirect string, offset: 0x303): rhlist_head
    <9d7>   DW_AT_declaration : 1
 <1><9d7>: Abbrev Number: 29 (DW_TAG_structure_type)
    <9d8>   DW_AT_name        : (indirect string, offset: 0x27b4): rhashtable_compare_arg
    <9dc>   DW_AT_declaration : 1
 <1><9dc>: Abbrev Number: 17 (DW_TAG_pointer_type)
    <9dd>   DW_AT_byte_size   : 8
    <9dd>   DW_AT_type        : <0x9d7>
 <1><9e1>: Abbrev Number: 29 (DW_TAG_structure_type)
    <9e2>   DW_AT_name        : (indirect string, offset: 0x2ce3): rhashtable_params
    <9e6>   DW_AT_declaration : 1
--
    <f2f>   DW_AT_type        : <0x9c8>
    <f33>   DW_AT_data_member_location: 0
 <2><f34>: Abbrev Number: 39 (DW_TAG_member)
    <f35>   DW_AT_name        : (indirect string, offset: 0x25e): b_rhash_key
    <f39>   DW_AT_decl_file   : 46
    <f39>   DW_AT_decl_line   : 148
    <f3a>   DW_AT_decl_column : 15
    <f3b>   DW_AT_type        : <0xcb1>
    <f3f>   DW_AT_data_member_location: 8
 <2><f40>: Abbrev Number: 39 (DW_TAG_member)
    <f41>   DW_AT_name        : (indirect string, offset: 0x3fbd): b_length
    <f45>   DW_AT_decl_file   : 46
    <f45>   DW_AT_decl_line   : 149
--
    <1fa9>   DW_AT_type        : <0x9c8>
 <1><1fad>: Abbrev Number: 33 (DW_TAG_subprogram)
    <1fae>   DW_AT_external    : 1
    <1fae>   DW_AT_name        : (indirect string, offset: 0x5b66): __SCT__tp_func_xfs_buf_backing_vmalloc
    <1fb2>   DW_AT_decl_file   : 3
    <1fb3>   DW_AT_decl_line   : 793
    <1fb5>   DW_AT_decl_column : 1
    <1fb6>   DW_AT_prototyped  : 1
    <1fb6>   DW_AT_type        : <0x6e>
    <1fba>   DW_AT_declaration : 1
    <1fba>   DW_AT_sibling     : <0x1fce>
 <2><1fbe>: Abbrev Number: 6 (DW_TAG_formal_parameter)
    <1fbf>   DW_AT_type        : <0x27f>


> iacme@number:~$ readelf -wi git/build/allmodconfig/fs/xfs/xfs_buf.o  | grep '<5b42>' -A4
>  <1><5b42>: Abbrev Number: 8 (DW_TAG_pointer_type)
>     <5b43>   DW_AT_byte_size   : 8
>     <5b43>   DW_AT_type        : <0x5b22>
>  <1><5b47>: Abbrev Number: 30 (DW_TAG_structure_type)
>     <5b48>   DW_AT_name        : (indirect string, offset: 0x14c84): rhlist_head

hch@brick:~/work/xfs$ readelf -wi fs/xfs/xfs_buf.o  | grep '<0x9c8>' -A4
    <9ce>   DW_AT_type        : <0x9c8>
 <1><9d2>: Abbrev Number: 29 (DW_TAG_structure_type)
    <9d3>   DW_AT_name        : (indirect string, offset: 0x303): rhlist_head
    <9d7>   DW_AT_declaration : 1
 <1><9d7>: Abbrev Number: 29 (DW_TAG_structure_type)
--
    <f2f>   DW_AT_type        : <0x9c8>
    <f33>   DW_AT_data_member_location: 0
 <2><f34>: Abbrev Number: 39 (DW_TAG_member)
    <f35>   DW_AT_name        : (indirect string, offset: 0x25e): b_rhash_key
    <f39>   DW_AT_decl_file   : 46
--
    <1fa9>   DW_AT_type        : <0x9c8>
 <1><1fad>: Abbrev Number: 33 (DW_TAG_subprogram)
    <1fae>   DW_AT_external    : 1
    <1fae>   DW_AT_name        : (indirect string, offset: 0x5b66): __SCT__tp_func_xfs_buf_backing_vmalloc
    <1fb2>   DW_AT_decl_file   : 3


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: pahole treats embedded structures a holes
  2026-05-29  4:02       ` Christoph Hellwig
@ 2026-05-29 19:28         ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 7+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-05-29 19:28 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: dwarves

On Fri, May 29, 2026 at 06:02:10AM +0200, Christoph Hellwig wrote:
> On Thu, May 28, 2026 at 04:48:44PM -0300, Arnaldo Carvalho de Melo wrote:
> > acme@number:~$ readelf -wi git/build/allmodconfig/fs/xfs/xfs_buf.o  | grep -m1 DW_AT_producer
 
> hch@brick:~/work/xfs$ readelf -wi fs/xfs/xfs_buf.o  | grep -m1 DW_AT_producer
>     <d>   DW_AT_producer    : (indirect string, offset: 0x6012): GNU C11 15.2.0 -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx -mno-sse4a -m64 -mno-80387 -mno-fp-ret-in-387 -mpreferred-stack-boundary=3 -mskip-rax-setup -march=x86-64 -mtune=generic -mno-red-zone -mcmodel=kernel -mstack-protector-guard-reg=gs -mstack-protector-guard-symbol=__ref_stack_chk_guard -mindirect-branch=thunk-extern -mindirect-branch-register -mindirect-branch-cs-prefix -mfunction-return=thunk-extern -g -gdwarf-5 -O2 -std=gnu11 -fshort-wchar -funsigned-char -fno-common -fno-PIE -fno-strict-aliasing -fms-extensions -fcf-protection=branch -falign-jumps=1 -falign-loops=1 -fno-asynchronous-unwind-tables -fno-jump-tables -fpatchable-function-entry=16,16 -fno-delete-null-pointer-checks -fno-allow-store-data-races -fstack-protector-strong -fomit-frame-pointer -fzero-init-padding-bits=all -fno-stack-clash-protection -fmin-function-alignment=16 -fstrict-flex-arrays=3 -fno-strict-overflow -fstack-check=no -fconserve-stack -fno-builtin-wcslen -fno-var-tracking -femit-struct-debug-baseonly

> > then, please take a look at this sequence:

> > acme@number:~$ readelf -wi git/build/allmodconfig/fs/xfs/xfs_buf.o  | grep -w xfs_buf$ -B1 -A12
 
> hch@brick:~/work/xfs$ readelf -wi fs/xfs/xfs_buf.o  | grep -w xfs_buf$ -B1 -A12
>  <1><f1c>: Abbrev Number: 93 (DW_TAG_structure_type)
>     <f1d>   DW_AT_name        : (indirect string, offset: 0x3358): xfs_buf
>     <f21>   DW_AT_byte_size   : 344
>     <f23>   DW_AT_alignment   : 8
>     <f23>   DW_AT_decl_file   : 46
>     <f23>   DW_AT_decl_line   : 138
>     <f24>   DW_AT_decl_column : 8
>     <f24>   DW_AT_sibling     : <0x10a2>
>  <2><f28>: Abbrev Number: 39 (DW_TAG_member)
>     <f29>   DW_AT_name        : (indirect string, offset: 0x5e80): b_rhash_head
>     <f2d>   DW_AT_decl_file   : 46
>     <f2d>   DW_AT_decl_line   : 146
>     <f2e>   DW_AT_decl_column : 20
>     <f2f>   DW_AT_type        : <0x9c8>
 
> > acme@number:~$ readelf -wi git/build/allmodconfig/fs/xfs/xfs_buf.o  | grep '<5b22>' -A12
 
> hch@brick:~/work/xfs$ readelf -wi fs/xfs/xfs_buf.o  | grep '<0x9c8>' -A12

This part is the tricky one, see that the 0x isn't there inside the
<TYPE> in my grep, I guess whoever wrote readelf used this to get the
offset, not the many entries pointing to it :-)

You need to do this:

hch@brick:~/work/xfs$ readelf -wi fs/xfs/xfs_buf.o  | grep '<9c8>' -A12

Without the 0x, so that I can see what is the type for that member.

Or better, please send me your fs/xfs/xfs_buf.o, that will be easier,
I'll try it myself, and if I reproduce your results, I'll be able to fix
it and test on the same fs/xfs/xfs_buf.o file.

- Arnaldo

>     <9ce>   DW_AT_type        : <0x9c8>
>  <1><9d2>: Abbrev Number: 29 (DW_TAG_structure_type)
>     <9d3>   DW_AT_name        : (indirect string, offset: 0x303): rhlist_head
>     <9d7>   DW_AT_declaration : 1
>  <1><9d7>: Abbrev Number: 29 (DW_TAG_structure_type)
>     <9d8>   DW_AT_name        : (indirect string, offset: 0x27b4): rhashtable_compare_arg
>     <9dc>   DW_AT_declaration : 1
>  <1><9dc>: Abbrev Number: 17 (DW_TAG_pointer_type)
>     <9dd>   DW_AT_byte_size   : 8
>     <9dd>   DW_AT_type        : <0x9d7>
>  <1><9e1>: Abbrev Number: 29 (DW_TAG_structure_type)
>     <9e2>   DW_AT_name        : (indirect string, offset: 0x2ce3): rhashtable_params
>     <9e6>   DW_AT_declaration : 1
> --
>     <f2f>   DW_AT_type        : <0x9c8>
>     <f33>   DW_AT_data_member_location: 0
>  <2><f34>: Abbrev Number: 39 (DW_TAG_member)
>     <f35>   DW_AT_name        : (indirect string, offset: 0x25e): b_rhash_key
>     <f39>   DW_AT_decl_file   : 46
>     <f39>   DW_AT_decl_line   : 148
>     <f3a>   DW_AT_decl_column : 15
>     <f3b>   DW_AT_type        : <0xcb1>
>     <f3f>   DW_AT_data_member_location: 8
>  <2><f40>: Abbrev Number: 39 (DW_TAG_member)
>     <f41>   DW_AT_name        : (indirect string, offset: 0x3fbd): b_length
>     <f45>   DW_AT_decl_file   : 46
>     <f45>   DW_AT_decl_line   : 149
> --
>     <1fa9>   DW_AT_type        : <0x9c8>
>  <1><1fad>: Abbrev Number: 33 (DW_TAG_subprogram)
>     <1fae>   DW_AT_external    : 1
>     <1fae>   DW_AT_name        : (indirect string, offset: 0x5b66): __SCT__tp_func_xfs_buf_backing_vmalloc
>     <1fb2>   DW_AT_decl_file   : 3
>     <1fb3>   DW_AT_decl_line   : 793
>     <1fb5>   DW_AT_decl_column : 1
>     <1fb6>   DW_AT_prototyped  : 1
>     <1fb6>   DW_AT_type        : <0x6e>
>     <1fba>   DW_AT_declaration : 1
>     <1fba>   DW_AT_sibling     : <0x1fce>
>  <2><1fbe>: Abbrev Number: 6 (DW_TAG_formal_parameter)
>     <1fbf>   DW_AT_type        : <0x27f>
> 
> 
> > iacme@number:~$ readelf -wi git/build/allmodconfig/fs/xfs/xfs_buf.o  | grep '<5b42>' -A4
> >  <1><5b42>: Abbrev Number: 8 (DW_TAG_pointer_type)
> >     <5b43>   DW_AT_byte_size   : 8
> >     <5b43>   DW_AT_type        : <0x5b22>
> >  <1><5b47>: Abbrev Number: 30 (DW_TAG_structure_type)
> >     <5b48>   DW_AT_name        : (indirect string, offset: 0x14c84): rhlist_head
> 
> hch@brick:~/work/xfs$ readelf -wi fs/xfs/xfs_buf.o  | grep '<0x9c8>' -A4
>     <9ce>   DW_AT_type        : <0x9c8>
>  <1><9d2>: Abbrev Number: 29 (DW_TAG_structure_type)
>     <9d3>   DW_AT_name        : (indirect string, offset: 0x303): rhlist_head
>     <9d7>   DW_AT_declaration : 1
>  <1><9d7>: Abbrev Number: 29 (DW_TAG_structure_type)
> --
>     <f2f>   DW_AT_type        : <0x9c8>
>     <f33>   DW_AT_data_member_location: 0
>  <2><f34>: Abbrev Number: 39 (DW_TAG_member)
>     <f35>   DW_AT_name        : (indirect string, offset: 0x25e): b_rhash_key
>     <f39>   DW_AT_decl_file   : 46
> --
>     <1fa9>   DW_AT_type        : <0x9c8>
>  <1><1fad>: Abbrev Number: 33 (DW_TAG_subprogram)
>     <1fae>   DW_AT_external    : 1
>     <1fae>   DW_AT_name        : (indirect string, offset: 0x5b66): __SCT__tp_func_xfs_buf_backing_vmalloc
>     <1fb2>   DW_AT_decl_file   : 3

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: pahole treats embedded structures a holes
@ 2026-06-05 19:28 Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 7+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-06-05 19:28 UTC (permalink / raw)
  To: dwarves

FYI and documentation. I'll work on looking at the DW_AT_producer tag
for those compiler options to show in the pretty printing output, as
well as checking potential implications for BTF generation, but I think
that one will end up being harmless because of the combination of all
DWARF CUs the types suppressed by CU would eventually be resolved.

- Arnaldo

----- Forwarded message from Arnaldo Carvalho de Melo <acme@kernel.org> -----

Date: Mon, 1 Jun 2026 12:18:58 -0300
From: Arnaldo Carvalho de Melo <acme@kernel.org>
To: Christoph Hellwig <hch@lst.de>
Subject: Re: pahole treats embedded structures a holes
Message-ID: <ah2i4lHbSgilDxQd@x1>

On Sat, May 30, 2026 at 05:22:20AM +0200, Christoph Hellwig wrote:
> Here is a compressed xfs_buf.o.  I don't think it's the same as before,
> but it shows the same symptoms.

TIL: -femit-struct-debug-baseonly

TLDR; you enabled CONFIG_DEBUG_INFO_REDUCED while distros use:

acme@x1:~/git/linux$ grep CONFIG_DEBUG_INFO_ /lib/modules/`uname -r`/config
# CONFIG_DEBUG_INFO_NONE is not set
CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
# CONFIG_DEBUG_INFO_DWARF4 is not set
# CONFIG_DEBUG_INFO_DWARF5 is not set
# CONFIG_DEBUG_INFO_REDUCED is not set
CONFIG_DEBUG_INFO_COMPRESSED_NONE=y
# CONFIG_DEBUG_INFO_COMPRESSED_ZLIB is not set
# CONFIG_DEBUG_INFO_SPLIT is not set
CONFIG_DEBUG_INFO_BTF=y
CONFIG_DEBUG_INFO_BTF_MODULES=y
acme@x1:~/git/linux$

I'm adding a TODO entry to notice that and add a comment at that point
stating that the type for a embedded struct wasn't found and that the
user probably is using -femit-struct-debug-baseonly and maybe
CONFIG_DEBUG_INFO_REDUCED.

Please consider replying with this message to the mailing list to leave
this documented in the archives :-)

- Arnaldo

Longer analysis:

acme@x1:~$ pahole -C xfs_buf xfs_buf.o  | head
struct xfs_buf {
	struct rhash_head          b_rhash_head;         /*     0     0 */

	/* XXX 8 bytes hole, try to pack */

	xfs_daddr_t                b_rhash_key;          /*     8     8 */
	int                        b_length;             /*    16     4 */

	/* XXX 4 bytes hole, try to pack */

acme@x1:~$ pahole -C b_rhash_head xfs_buf.o 
pahole: type 'b_rhash_head' not found
acme@x1:~$ pahole -C xfs_buf xfs_buf.o  | head
struct xfs_buf {
	struct rhash_head          b_rhash_head;         /*     0     0 */

	/* XXX 8 bytes hole, try to pack */

	xfs_daddr_t                b_rhash_key;          /*     8     8 */
	int                        b_length;             /*    16     4 */

	/* XXX 4 bytes hole, try to pack */

acme@x1:~$ pahole -C rhash_head xfs_buf.o 
pahole: type 'rhash_head' not found
acme@x1:~$

acme@x1:~$ readelf -wi xfs_buf.o | grep DW_AT_producer
    <d>   DW_AT_producer    : (indirect string, offset: 0x28e6): GNU C11 15.2.0 -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx -mno-sse4a -m64 -mno-80387 -mno-fp-ret-in-387 -mpreferred-stack-boundary=3 -mskip-rax-setup -march=x86-64 -mtune=generic -mno-red-zone -mcmodel=kernel -mstack-protector-guard-reg=gs -mstack-protector-guard-symbol=__ref_stack_chk_guard -mindirect-branch=thunk-extern -mindirect-branch-register -mindirect-branch-cs-prefix -mfunction-return=thunk-extern -g -O2 -std=gnu11 -fshort-wchar -funsigned-char -fno-common -fno-PIE -fno-strict-aliasing -fms-extensions -fcf-protection=branch -falign-jumps=1 -falign-loops=1 -fno-asynchronous-unwind-tables -fno-jump-tables -fpatchable-function-entry=16,16 -fno-delete-null-pointer-checks -fno-allow-store-data-races -fstack-protector-strong -fomit-frame-pointer -fzero-init-padding-bits=all -fno-stack-clash-protection -fmin-function-alignment=16 -fstrict-flex-arrays=3 -fno-strict-overflow -fstack-check=no -fconserve-stack -fno-builtin-wcslen -fno-var-tracking -femit-struct-debug-baseonly
acme@x1:~$

acme@x1:~/git/linux$ git grep -B4 -A4 -- -femit-struct-debug-baseonly
rust/Makefile-  -mno-pointers-to-nested-functions -mno-string \
rust/Makefile-  -mno-strict-align -mstrict-align -mdirect-extern-access \
rust/Makefile-  -mexplicit-relocs -mno-check-zero-division \
rust/Makefile-  -fconserve-stack -falign-jumps=% -falign-loops=% \
rust/Makefile:  -femit-struct-debug-baseonly -fno-ipa-cp-clone -fno-ipa-sra \
rust/Makefile-  -fno-partial-inlining -fplugin-arg-arm_ssp_per_task_plugin-% \
rust/Makefile-  -fno-reorder-blocks -fno-allow-store-data-races -fasan-shadow-offset=% \
rust/Makefile-  -fzero-call-used-regs=% -fno-stack-clash-protection \
rust/Makefile-  -fno-inline-functions-called-once -fsanitize=bounds-strict \
--
scripts/Makefile.debug-ifdef CONFIG_DEBUG_INFO_REDUCED
scripts/Makefile.debug-DEBUG_CFLAGS     += -fno-var-tracking
scripts/Makefile.debug-DEBUG_RUSTFLAGS  += -Cdebuginfo=1
scripts/Makefile.debug-ifdef CONFIG_CC_IS_GCC
scripts/Makefile.debug:DEBUG_CFLAGS     += -femit-struct-debug-baseonly
scripts/Makefile.debug-endif
scripts/Makefile.debug-else
scripts/Makefile.debug-DEBUG_RUSTFLAGS  += -Cdebuginfo=2
scripts/Makefile.debug-endif
acme@x1:~/git/linux$

----- 8< -----
-femit-struct-debug-baseonly is a GCC (GNU Compiler Collection)
command-line flag used to drastically reduce the size of object files by
limiting the amount of debug information generated for structures,
unions, and classes.

It works by strictly filtering which type definitions are included in
the final DWARF debug symbols based on where those types are
declared.

How it Works

When you compile a source file (e.g., main.c), the compiler normally
emits debug information for all types used or declared within that file,
including those from deeply nested external header files.

With -femit-struct-debug-baseonly enabled, GCC uses aggressive filtering
rules:

Matches Base File Name: Debug information is only generated for
structs/unions/classes if the base name of the file where the type is
declared matches the base name of the file being compiled.

Practical Example:

If you are compiling foo.c, debug symbols will only be generated for
types declared directly inside foo.c and its direct companion header
foo.h. Types declared in other included headers (like standard_lib.h)
are completely ignored.

Key Benefits

Smaller Binaries:

It severely reduces the storage footprint of debug ELF and object files.

Faster Link Times:

Less debug information means linkers have less data to process and
deduplicate.

Faster Debugger Loading:

Debuggers like GDB or IDE symbol loaders can load the project
significantly faster.

Caveats & Constraints

Limited Debugging Visibility:

Because it aggressively strips type data, your debugger might not
recognize or be able to pretty-print structures declared in external
files or libraries during a live debugging session.

Format Restriction: This flag exclusively functions with DWARF debug
output format.

Alternative Flags: It is a stricter, more aggressive variant of
-femit-struct-debug-reduced.

If you require fine-grained control, you can instead use
-femit-struct-debug-detailed.

----- 8< -----

----- End forwarded message -----

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-06-05 19:28 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-28  5:11 pahole treats embedded structures a holes Christoph Hellwig
2026-05-28 13:39 ` Arnaldo Carvalho de Melo
2026-05-28 13:58   ` Christoph Hellwig
2026-05-28 19:48     ` Arnaldo Carvalho de Melo
2026-05-29  4:02       ` Christoph Hellwig
2026-05-29 19:28         ` Arnaldo Carvalho de Melo
  -- strict thread matches above, loose matches on Subject: below --
2026-06-05 19:28 Arnaldo Carvalho de Melo

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.