From: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx> For instance, this one has embedded flexible arrays: $ pahole lirc_fh struct lirc_fh { struct list_head list; /* 0 16 */ struct rc_dev * rc; /* 16 8 */ int carrier_low; /* 24 4 */ /* XXX 4 bytes hole, try to pack */ struct { union { struct __kfifo kfifo; /* 32 24 */ unsigned int * type; /* 32 8 */ const unsigned int * const_type; /* 32 8 */ char * rectype; /* 32 8 */ unsigned int * ptr; /* 32 8 */ const unsigned int * ptr_const; /* 32 8 */ }; /* 32 24 */ unsigned int buf[]; /* 56 0 */ } rawir; /* 32 24 */ /* XXX last struct has a flexible array */ struct { union { struct __kfifo kfifo; /* 56 24 */ struct lirc_scancode * type; /* 56 8 */ const struct lirc_scancode * const_type; /* 56 8 */ char * rectype; /* 56 8 */ struct lirc_scancode * ptr; /* 56 8 */ const struct lirc_scancode * ptr_const; /* 56 8 */ }; /* 56 24 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ struct lirc_scancode buf[]; /* 80 0 */ } scancodes; /* 56 24 */ /* XXX last struct has a flexible array */ wait_queue_head_t wait_poll; /* 80 24 */ u8 send_mode; /* 104 1 */ u8 rec_mode; /* 105 1 */ /* size: 112, cachelines: 2, members: 8 */ /* sum members: 102, holes: 1, sum holes: 4 */ /* padding: 6 */ /* flexible array members: end: 2 */ /* last cacheline: 48 bytes */ }; $ 'end' means that the members with flexible arrays have them in the "classical" sense, i.e. the last member of those member types is a [] member. When 'middle' appears it means another level, just like the above 'struct lirc_fh' has multiple members in its midle that are flexible arrays. If we use 'pahole --with_embedded_flexible_array' we'll see quite a few in the Linux kernel (using BTF info from /sys/kernel/btf/vmlinux, mostly available in most kernels these days), using --sizes so that we get just one line per Linux kernel struct that have embedded flexible arrays (and its sizes and number of alignment holes, as bonuses): $ pahole --sizes --with_embedded_flexible_array | head mem_cgroup 2240 10 pglist_data 175424 7 zone 1728 5 cgroup 1984 3 cgroup_root 6272 1 page_counter 192 1 cpu_hw_events 5200 6 crypto_shash 40 1 crypto_aead 40 0 crypto_ahash 48 2 $ $ pahole crypto_shash struct crypto_shash { unsigned int descsize; /* 0 4 */ /* XXX 4 bytes hole, try to pack */ struct crypto_tfm base; /* 8 32 */ /* XXX last struct has a flexible array, 1 hole */ /* size: 40, cachelines: 1, members: 2 */ /* sum members: 36, holes: 1, sum holes: 4 */ /* member types with holes: 1, total: 1 */ /* flexible array members: end: 1 */ /* last cacheline: 40 bytes */ }; $ If we expand it all: $ pahole -E crypto_shash struct crypto_shash { unsigned int descsize; /* 0 4 */ /* XXX 4 bytes hole, try to pack */ struct crypto_tfm { /* typedef refcount_t */ struct refcount_struct { /* typedef atomic_t */ struct { int counter; /* 8 4 */ } refs; /* 8 4 */ } refcnt; /* 8 4 */ /* typedef u32 -> __u32 */ unsigned int crt_flags; /* 12 4 */ int node; /* 16 4 */ /* XXX 4 bytes hole, try to pack */ void (*exit)(struct crypto_tfm *); /* 24 8 */ struct crypto_alg * __crt_alg; /* 32 8 */ void * __crt_ctx[]; /* 40 0 */ } base; /* 8 32 */ /* XXX last struct has a flexible array, 1 hole */ /* size: 40, cachelines: 1, members: 2 */ /* sum members: 36, holes: 1, sum holes: 4 */ /* member types with holes: 1, total: 1 */ /* flexible array members: end: 1 */ /* last cacheline: 40 bytes */ }; $ Interesting, but we don't see the "middle" case... Maybe 'struct cgroup'? $ pahole cgroup | tail struct cgroup * ancestors[]; /* 1984 0 */ /* size: 1984, cachelines: 31, members: 42 */ /* sum members: 1952, holes: 3, sum holes: 32 */ /* member types with holes: 3, total: 3 */ /* paddings: 1, sum paddings: 4 */ /* forced alignments: 1 */ /* flexible array members: end: 1 */ }; $ Humm, maybe some data structure embeds 'struct cgroup'? Lets see with: $ pahole --contains cgroup cgroup_root $ A-ha, finally that 'middle' stat: $ pahole cgroup_root struct cgroup_root { struct kernfs_root * kf_root; /* 0 8 */ unsigned int subsys_mask; /* 8 4 */ int hierarchy_id; /* 12 4 */ struct list_head root_list; /* 16 16 */ struct callback_head rcu; /* 32 16 */ /* XXX 16 bytes hole, try to pack */ /* --- cacheline 1 boundary (64 bytes) --- */ struct cgroup cgrp __attribute__((__aligned__(64))); /* 64 1984 */ /* XXX last struct has a flexible array, embedded flexible array(s), 3 holes */ /* --- cacheline 32 boundary (2048 bytes) --- */ struct cgroup * cgrp_ancestor_storage; /* 2048 8 */ atomic_t nr_cgrps; /* 2056 4 */ unsigned int flags; /* 2060 4 */ char release_agent_path[4096]; /* 2064 4096 */ /* --- cacheline 96 boundary (6144 bytes) was 16 bytes ago --- */ char name[64]; /* 6160 64 */ /* size: 6272, cachelines: 98, members: 11 */ /* sum members: 6208, holes: 1, sum holes: 16 */ /* padding: 48 */ /* member types with holes: 1, total: 3 */ /* forced alignments: 1, forced holes: 1, sum forced holes: 16 */ /* flexible array members: end: 1, middle: 1 */ } __attribute__((__aligned__(64))); $ Cc: "Gustavo A. R. Silva" <gustavoars@xxxxxxxxxx> Cc: Willy Tarreau <w@xxxxxx> Signed-off-by: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx> --- dwarves_fprintf.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/dwarves_fprintf.c b/dwarves_fprintf.c index 0d642a318fd836ef..e16a6b4da65ed2cd 100644 --- a/dwarves_fprintf.c +++ b/dwarves_fprintf.c @@ -1502,6 +1502,8 @@ struct member_types_holes { uint16_t nr_with_bit_holes; uint16_t total_nr_holes; uint16_t total_nr_bit_holes; + uint16_t nr_flexible_array_members; + uint16_t nr_embedded_flexible_array_members; uint32_t sum_paddings; uint32_t sum_bit_paddings; }; @@ -1540,11 +1542,13 @@ static size_t class__fprintf_member_type_holes(struct class *class, const struct if (has_flexible_array) { printed += fprintf(fp, " a flexible array"); + ++holes->nr_flexible_array_members; first = false; } if (has_embedded_flexible_array) { printed += fprintf(fp, "%s embedded flexible array(s)", first ? "" : ","); + ++holes->nr_embedded_flexible_array_members; first = false; } @@ -1985,6 +1989,22 @@ next_member: } printed += fprintf(fp, " */\n"); } + if (member_types_holes.nr_flexible_array_members > 0 || + member_types_holes.nr_embedded_flexible_array_members > 0) { + printed += fprintf(fp, "%.*s/* flexible array members: ", + cconf.indent, tabs); + + if (member_types_holes.nr_flexible_array_members > 0) + printed += fprintf(fp, "end: %u", member_types_holes.nr_flexible_array_members); + + if (member_types_holes.nr_embedded_flexible_array_members > 0) { + printed += fprintf(fp, "%smiddle: %u", + member_types_holes.nr_flexible_array_members ? ", " : "", + member_types_holes.nr_embedded_flexible_array_members); + } + + printed += fprintf(fp, " */\n"); + } cacheline = (cconf.base_offset + type->size) % conf_fprintf__cacheline_size(conf); if (cacheline != 0) printed += fprintf(fp, "%.*s/* last cacheline: %u bytes */\n", -- 2.46.0