From: Yonghong Song <yonghong.song@linux.dev>
To: Arnaldo Carvalho de Melo <acme@kernel.org>,
Alan Maguire <alan.maguire@oracle.com>
Cc: Jiri Olsa <jolsa@kernel.org>,
Clark Williams <williams@redhat.com>,
dwarves@vger.kernel.org, bpf@vger.kernel.org,
Andrii Nakryiko <andrii@kernel.org>,
Mark Wieelard <mjw@redhat.com>,
Arnaldo Carvalho de Melo <acme@redhat.com>
Subject: Re: [PATCH 04/12] btf_encoder: Encode variant parts as union members in BTF
Date: Mon, 10 Aug 2026 17:29:56 -0700 [thread overview]
Message-ID: <76eba899-aad9-40ba-969f-bfec28031e12@linux.dev> (raw)
In-Reply-To: <20260731193102.110693-5-acme@kernel.org>
On 7/31/26 12:30 PM, Arnaldo Carvalho de Melo wrote:
> From: Arnaldo Carvalho de Melo <acme@redhat.com>
>
> With the DWARF loader now populating DW_TAG_variant children (previous
> commit), wire them into BTF encoding so Rust discriminated unions
> (Option<T>, Result<T,E>, etc.) are no longer emitted as empty structs.
>
> Two changes:
>
> 1. Struct-to-union promotion: when a DW_TAG_structure_type has
> variant_parts but no regular data members, encode it as BTF_KIND_UNION
> instead of BTF_KIND_STRUCT, since the variants overlap at offset 0.
>
> 2. Variant member encoding: after encoding regular data members, iterate
> the variant_parts and emit each variant as a BTF union field with the
> variant's name and resolved type reference.
>
> Testing with the sashiko-cli Rust binary (a real-world async HTTP client
> using tokio, hyper, serde, etc.):
>
> Before:
>
> $ bpftool btf dump file sashiko-cli | grep -c UNION
> 2073
> $ bpftool btf dump file sashiko-cli | grep 'STRUCT.*vlen=0' | grep -vc 'size=0'
> 24335
>
> After:
>
> $ bpftool btf dump file sashiko-cli | grep -c UNION
> 25750
> $ bpftool btf dump file sashiko-cli | grep 'STRUCT.*vlen=0' | grep -vc 'size=0'
> 2236
>
> 22,099 types that were previously encoded as empty structs are now
> properly represented as unions with their variant members:
>
> Before:
>
> $ bpftool btf dump file code_with_type.o | grep -A1 'Option<u32>'
> [11] STRUCT 'Option<u32>' size=8 vlen=0
>
> After:
>
> $ bpftool btf dump file code_with_type.o | grep -A3 'Option<u32>'
> [11] UNION 'Option<u32>' size=8 vlen=2
> 'None' type_id=9 bits_offset=0
> 'Some' type_id=10 bits_offset=0
FYI, the below is for llvm bpf backend to handle DW_TAG_variant_part
to generate BTF.
link: https://github.com/llvm/llvm-project/pull/155783
For a rust code like:
; Source:
; #![no_std]
; #![no_main]
;
; pub enum MyEnum {
; First { a: u32, b: i32 },
; Second(u32),
; }
;
; #[unsafe(no_mangle)]
; pub static X: MyEnum = MyEnum::First { a: 54, b: -23 };
;
; #[cfg(not(test))]
; #[panic_handler]
; fn panic(_info: &core::panic::PanicInfo) -> ! {
; loop {}
; }
The BTF encoding:
; CHECK-BTF: [1] STRUCT 'MyEnum' size=12 vlen=1
; CHECK-BTF-NEXT: '(anon)' type_id=3 bits_offset=0
; CHECK-BTF-NEXT: [2] INT 'u32' size=4 bits_offset=0 nr_bits=32 encoding=(none)
; CHECK-BTF-NEXT: [3] UNION '(anon)' size=12 vlen=3
; CHECK-BTF-NEXT: '(anon)' type_id=2 bits_offset=0
; CHECK-BTF-NEXT: 'First' type_id=4 bits_offset=0
; CHECK-BTF-NEXT: 'Second' type_id=6 bits_offset=0
; CHECK-BTF-NEXT: [4] STRUCT 'First' size=12 vlen=2
; CHECK-BTF-NEXT: 'a' type_id=2 bits_offset=32
; CHECK-BTF-NEXT: 'b' type_id=5 bits_offset=64
; CHECK-BTF-NEXT: [5] INT 'i32' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED
; CHECK-BTF-NEXT: [6] STRUCT 'Second' size=12 vlen=1
; CHECK-BTF-NEXT: '__0' type_id=2 bits_offset=32
; CHECK-BTF-NEXT: [7] VAR 'X' type_id=1, linkage=global
; CHECK-BTF-NEXT: [8] DATASEC '.rodata' size=0 vlen=1
; CHECK-BTF-NEXT: type_id=7 offset=0 size=12
>
> Assisted-by: Claude:claude-sonnet-4-5
> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
> ---
> btf_encoder.c | 37 +++++++++++++++++++++++++++++++++++--
> 1 file changed, 35 insertions(+), 2 deletions(-)
>
> diff --git a/btf_encoder.c b/btf_encoder.c
> index 83ce21186ea7da36..acf0a5ade5e29014 100644
> --- a/btf_encoder.c
> +++ b/btf_encoder.c
> @@ -1855,6 +1855,12 @@ static void dump_invalid_symbol(const char *msg, const char *sym,
> fprintf(stderr, "PAHOLE: Error: Use '--btf_encode_force' to ignore such symbols and force emit the btf.\n");
> }
>
> +static bool type__has_variant_parts(const struct type *type)
> +{
> + return !list_empty(&type->variant_parts);
> +}
> +
> +
> static int32_t btf_encoder__add_struct_type(struct btf_encoder *encoder, struct tag *tag)
> {
> struct type *type = tag__type(tag);
> @@ -1863,8 +1869,18 @@ static int32_t btf_encoder__add_struct_type(struct btf_encoder *encoder, struct
> int32_t type_id;
> uint8_t kind;
>
> - kind = (tag->tag == DW_TAG_union_type) ?
> - BTF_KIND_UNION : BTF_KIND_STRUCT;
> + /*
> + * Rust discriminated unions (enums) are represented in DWARF as
> + * DW_TAG_structure_type with DW_TAG_variant_part children.
> + * If the struct has only variant parts and no regular data members,
> + * encode it as a BTF union since the variants overlap at offset 0.
> + */
> + if (tag->tag == DW_TAG_union_type)
> + kind = BTF_KIND_UNION;
> + else if (type__has_variant_parts(type) && type->nr_members == 0)
> + kind = BTF_KIND_UNION;
> + else
> + kind = BTF_KIND_STRUCT;
>
> type_id = btf_encoder__add_struct(encoder, kind, name, type->size);
> if (type_id < 0)
> @@ -1882,6 +1898,23 @@ static int32_t btf_encoder__add_struct_type(struct btf_encoder *encoder, struct
> return -1;
> }
>
> + if (type__has_variant_parts(type) && kind == BTF_KIND_UNION) {
> + struct variant_part *vpart;
> +
> + type__for_each_variant_part(type, vpart) {
> + struct variant *variant;
> +
> + variant_part__for_each_variant(vpart, variant) {
> + if (variant->tag.type == 0)
> + continue;
> +
> + uint32_t ref_type_id = btf_encoder__tag_type(encoder, variant->tag.type);
> +
> + if (btf_encoder__add_field(encoder, variant->name, ref_type_id, 0, 0))
> + return -1;
> + }
> + }
> + }
>
>
> return type_id;
next prev parent reply other threads:[~2026-08-11 0:30 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-31 19:30 [PATCHES 00/12] pahole: Support more rust tags and references to dwz alternate debug files Arnaldo Carvalho de Melo
2026-07-31 19:30 ` [PATCH 01/12] dwarf_loader: Initial support for DW_TAG_variant_part Arnaldo Carvalho de Melo
2026-07-31 19:30 ` [PATCH 02/12] dwarf_loader: Initial support for DW_TAG_subprogram in DW_TAG_enumeration Arnaldo Carvalho de Melo
2026-07-31 19:30 ` [PATCH 03/12] dwarf_loader: Populate DW_TAG_variant children in DW_TAG_variant_part Arnaldo Carvalho de Melo
2026-07-31 19:30 ` [PATCH 04/12] btf_encoder: Encode variant parts as union members in BTF Arnaldo Carvalho de Melo
2026-08-11 0:29 ` Yonghong Song [this message]
2026-07-31 19:30 ` [PATCH 05/12] dwarf_loader: Handle DW_FORM_block in attr_numeric for Rust discriminant values Arnaldo Carvalho de Melo
2026-07-31 19:30 ` [PATCH 06/12] dwarf_loader: Allow forcing the merge of CUs for solving inter CU tag references Arnaldo Carvalho de Melo
2026-07-31 19:30 ` [PATCH 07/12] dwarf_loader: Support DW_TAG_imported_unit for same-file partial units Arnaldo Carvalho de Melo
2026-07-31 19:30 ` [PATCH 08/12] dwarf_loader: Fix cus__merging_cu failing to detect DW_FORM_ref_addr Arnaldo Carvalho de Melo
2026-07-31 19:30 ` [PATCH 09/12] dwarf_loader: Add cu parameter to tag__set_spec() and dwarf_tag__set_attr_type() Arnaldo Carvalho de Melo
2026-07-31 19:30 ` [PATCH 10/12] dwarf_loader: Support DW_FORM_GNU_ref_alt references to dwz alternate debug files Arnaldo Carvalho de Melo
2026-07-31 19:30 ` [PATCH 11/12] tests: Add inter-CU type reference comparison test Arnaldo Carvalho de Melo
2026-07-31 19:31 ` [PATCH 12/12] scripts: Add vmlinux_comparison.py for DWARF/BTF analysis Arnaldo Carvalho de Melo
2026-08-07 8:09 ` [PATCHES 00/12] pahole: Support more rust tags and references to dwz alternate debug files Alan Maguire
2026-08-07 12:43 ` Arnaldo Carvalho de Melo
2026-08-07 17:34 ` Miguel Ojeda
2026-08-07 18:53 ` Arnaldo Carvalho de Melo
2026-08-07 19:26 ` Gary Guo
2026-08-07 20:30 ` Arnaldo Carvalho de Melo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=76eba899-aad9-40ba-969f-bfec28031e12@linux.dev \
--to=yonghong.song@linux.dev \
--cc=acme@kernel.org \
--cc=acme@redhat.com \
--cc=alan.maguire@oracle.com \
--cc=andrii@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=dwarves@vger.kernel.org \
--cc=jolsa@kernel.org \
--cc=mjw@redhat.com \
--cc=williams@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.