Re: [PATCH] rust: Disallow BTF generation with Rust + LTO

Matthew Maurer
2025-01-09T22:42:03Z

On Thu, Jan 9, 2025 at 2:39 PM Arnaldo Carvalho de Melo <acme@kernel.org> wrote:
>
> On Thu, Jan 09, 2025 at 01:29:47PM -0300, Arnaldo Carvalho de Melo wrote:
> > On Thu, Jan 09, 2025 at 10:49:49AM -0500, Tamir Duberstein wrote:
> > > On Thu, Jan 9, 2025 at 10:47 AM Arnaldo Carvalho de Melo <acme@kernel.org> wrote:
> > > > I was thinking about it after reading this thread yesterday, i.e. we
> > > > could encode constructs from Rust that can be represented in BTF and
> > > > skip the ones that can't, pruning types that depend on non BTF
> > > > representable types, etc.
> >
> > > Yep, this is what bpf-linker does, along with some other things[0]. I
> > > highly recommend reading the code I linked to avoid re-discovering
> > > these things.
> >
> > Sure, thanks for pointing it out and suggest I read it while
> > experimenting with having the same concept in pahole, I'll try a quick
> > hack and then look at it to see how close I got to what you guys came up
> > with :-)
>
> So I didn't manage to work on this today, just this quick hack:
>
> ⬢ [acme@toolbox pahole]$ git diff
> diff --git a/btf_encoder.c b/btf_encoder.c
> index 78efd705333e2e52..5610e0902f2cd347 100644
> --- a/btf_encoder.c
> +++ b/btf_encoder.c
> @@ -1559,7 +1559,7 @@ static int btf_encoder__encode_tag(struct btf_encoder *encoder, struct tag *tag,
> default:
> fprintf(stderr, "Unsupported DW_TAG_%s(0x%x): type: 0x%x\n",
> dwarf_tag_name(tag->tag), tag->tag, ref_type_id);
> - return -1;
> + return 0;
> }
> }
>
> ⬢ [acme@toolbox pahole]$
>
> Which essentially encodes any DWARF tag that the BTF encoder doesn't
> know about into 'void'.
>
> Super quick hack, I still have to look at the implications, but some
> results:
>
> ⬢ [acme@toolbox pahole]$ cp ../build/rust-kernel/vmlinux vmlinux.rust
> ⬢ [acme@toolbox pahole]$ pahole --btf_encode vmlinux.rust
> die__process_class: tag not supported 0x33 (variant_part) at <4c9c589>!
> die__create_new_enumeration: DW_TAG_subprogram (0x2e) @ <0x4cb784b> not handled in a rust CU!
> tag__recode_dwarf_type: couldn't find name for function 0x4cd72bf, abstract_origin=0, specification=0x4cb784b
> ⬢ [acme@toolbox pahole]$
> ⬢ [acme@toolbox pahole]$ pahole -F btf vmlinux.rust | less
> ⬢ [acme@toolbox pahole]$
> ⬢ [acme@toolbox pahole]$
> ⬢ [acme@toolbox pahole]$ pahole -F btf vmlinux.rust | less
> ⬢ [acme@toolbox pahole]$
> ⬢ [acme@toolbox pahole]$ bpftool btf dump file vmlinux.rust | less
> ⬢ [acme@toolbox pahole]$ bpftool btf dump file vmlinux.rust | head
> [1] INT 'DW_ATE_signed_32' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED
> [2] INT 'DW_ATE_signed_64' size=8 bits_offset=0 nr_bits=64 encoding=SIGNED
> [3] INT 'DW_ATE_unsigned_1' size=1 bits_offset=0 nr_bits=8 encoding=(none)
> [4] INT 'DW_ATE_unsigned_8' size=1 bits_offset=0 nr_bits=8 encoding=(none)
> [5] INT 'DW_ATE_unsigned_64' size=8 bits_offset=0 nr_bits=64 encoding=(none)
> [6] INT 'DW_ATE_unsigned_32' size=4 bits_offset=0 nr_bits=32 encoding=(none)
> [7] STRUCT 'tracepoint' size=80 vlen=9
> 'name' type_id=8 bits_offset=0
> 'key' type_id=12 bits_offset=64
> 'static_call_key' type_id=23 bits_offset=192
> ⬢ [acme@toolbox pahole]$ bpftool btf dump file vmlinux.rust | tail
> type_id=12300 offset=226816 size=24 (VAR 'cfd_data')
> type_id=12301 offset=226880 size=8 (VAR 'call_single_queue')
> type_id=12302 offset=226944 size=32 (VAR 'csd_data')
> type_id=51838 offset=227008 size=832 (VAR 'softnet_data')
> type_id=54492 offset=227840 size=24 (VAR 'rt_uncached_list')
> type_id=55984 offset=227904 size=24 (VAR 'rt6_uncached_list')
> type_id=8094 offset=229376 size=64 (VAR 'vmw_steal_time')
> type_id=8810 offset=229440 size=64 (VAR 'apf_reason')
> type_id=8811 offset=229504 size=64 (VAR 'steal_time')
> type_id=8813 offset=229568 size=8 (VAR 'kvm_apic_eoi')
> ⬢ [acme@toolbox pahole]$ readelf -wi vmlinux.rust | grep DW_AT_producer | head
> <d> DW_AT_producer : (indexed string: 0): clang version 18.1.6 (Fedora 18.1.6-3.fc40)
> <1be5a> DW_AT_producer : (indexed string: 0): clang version 18.1.6 (Fedora 18.1.6-3.fc40)
> <1ec5b> DW_AT_producer : (indexed string: 0): clang version 18.1.6 (Fedora 18.1.6-3.fc40)
> <3bfd5> DW_AT_producer : (indexed string: 0): clang version 18.1.6 (Fedora 18.1.6-3.fc40)
> <3d11c> DW_AT_producer : (indexed string: 0): clang version 18.1.6 (Fedora 18.1.6-3.fc40)
> <4fcf0> DW_AT_producer : (indexed string: 0): clang version 18.1.6 (Fedora 18.1.6-3.fc40)
> <503d5> DW_AT_producer : (indexed string: 0): clang version 18.1.6 (Fedora 18.1.6-3.fc40)
> <5c067> DW_AT_producer : (indexed string: 0): clang version 18.1.6 (Fedora 18.1.6-3.fc40)
> <5c42e> DW_AT_producer : (indexed string: 0): clang version 18.1.6 (Fedora 18.1.6-3.fc40)
> <5efd9> DW_AT_producer : (indexed string: 0): clang version 18.1.6 (Fedora 18.1.6-3.fc40)
> ⬢ [acme@toolbox pahole]$ readelf -wi vmlinux.rust | grep DW_AT_lang | grep -i rust
> <4c91de1> DW_AT_language : 28 (Rust)
> <4ce66ea> DW_AT_language : 28 (Rust)
> <4cf2cfa> DW_AT_language : 28 (Rust)
> <4cf71a8> DW_AT_language : 28 (Rust)
> <4d2797d> DW_AT_language : 28 (Rust)
> <4d50f34> DW_AT_language : 28 (Rust)
> ⬢ [acme@toolbox pahole]$
>
> Compilation Unit @ offset 0x4c91dd1:
> Length: 0x54905 (32-bit)
> Version: 4
> Abbrev Offset: 0x244258
> Pointer Size: 8
> <0><4c91ddc>: Abbrev Number: 1 (DW_TAG_compile_unit)
> <4c91ddd> DW_AT_producer : (indirect string, offset: 0x282d41): clang LLVM (rustc version 1.80.0 (051478957 2024-07-21) (Fedora 1.80.0-1.fc40))
> <4c91de1> DW_AT_language : 28 (Rust)
> <4c91de3> DW_AT_name : (indirect string, offset: 0x282d91): /usr/lib/rustlib/src/rust/library/core/src/lib.rs/@/core.3f32dfd9e3bca37e-cgu.0
> <4c91de7> DW_AT_stmt_list : 0xa1d85f
> <4c91deb> DW_AT_comp_dir : (indirect string, offset: 0x2ebc6): /home/acme/git/build/rust-kernel
> <4c91def> DW_AT_low_pc : 0
> <4c91df7> DW_AT_ranges : 0x1e5f0
> <1><4c91dfb>: Abbrev Number: 2 (DW_TAG_variable)
> <4c91dfc> DW_AT_name : (indirect string, offset: 0x555b60): <usize as core::fmt::Debug>::{vtable}
> <4c91e00> DW_AT_type : <0x4c91e0e>
> <4c91e04> DW_AT_location : 9 byte block: 3 78 34 50 82 ff ff ff ff (DW_OP_addr: ffffffff82503478)
> <1><4c91e0e>: Abbrev Number: 3 (DW_TAG_structure_type)
> <4c91e0f> DW_AT_containing_type: <0x4c91e5a>
> <4c91e13> DW_AT_name : (indirect string, offset: 0x2b3380): <usize as core::fmt::Debug>::{vtable_type}
> <4c91e17> DW_AT_byte_size : 32
> <4c91e18> DW_AT_alignment : 8
> <2><4c91e19>: Abbrev Number: 4 (DW_TAG_member)
> <4c91e1a> DW_AT_name : (indirect string, offset: 0x313232): drop_in_place
> <4c91e1e> DW_AT_type : <0x4c91e46>
> <4c91e22> DW_AT_alignment : 8
> <4c91e23> DW_AT_data_member_location: 0
> <2><4c91e24>: Abbrev Number: 4 (DW_TAG_member)
> <4c91e25> DW_AT_name : (indirect string, offset: 0x570b7e): size
> <4c91e29> DW_AT_type : <0x4c91e5a>
>
> ⬢ [acme@toolbox pahole]$ pahole -F btf -C "<usize as core::fmt::Debug>::{vtable_type}" vmlinux.rust
> struct <usize as core::fmt::Debug>::{vtable_type} {
> __SANITIZED_FAKE_INT__ * drop_in_place; /* 0 8 */
> usize size; /* 8 8 */
> usize align; /* 16 8 */
> __SANITIZED_FAKE_INT__ * __method3; /* 24 8 */
>
> /* size: 32, cachelines: 1, members: 4 */
> /* last cacheline: 32 bytes */
> };
>
> ⬢ [acme@toolbox pahole]$
>
> ⬢ [acme@toolbox pahole]$ pahole -F btf -C '<core::fmt::Error as core::fmt::Debug>::{vtable_type}' vmlinux.rust
> struct <core::fmt::Error as core::fmt::Debug>::{vtable_type} {
> __SANITIZED_FAKE_INT__ * drop_in_place; /* 0 8 */
> usize size; /* 8 8 */
> usize align; /* 16 8 */
> __SANITIZED_FAKE_INT__ * __method3; /* 24 8 */
>
> /* size: 32, cachelines: 1, members: 4 */
> /* last cacheline: 32 bytes */
> };
>
> ⬢ [acme@toolbox pahole]$
>
> ⬢ [acme@toolbox pahole]$ pahole --show_decl_info -F dwarf -C Alignment vmlinux.rust
> die__process_class: tag not supported 0x33 (variant_part) at <4c9c589>!
> die__create_new_enumeration: DW_TAG_subprogram (0x2e) @ <0x4cb784b> not handled in a rust CU!
> tag__recode_dwarf_type: couldn't find name for function 0x4cd72bf, abstract_origin=0, specification=0x4cb784b
> /* Used at: /usr/lib/rustlib/src/rust/library/core/src/lib.rs/@/core.3f32dfd9e3bca37e-cgu.0 */
> /* <4c9c50c> (null):32530 */
> enum Alignment {
> Left = 0,
> Right = 1,
> Center = 2,
> Unknown = 3,
> } __attribute__((__packed__));
>
> ⬢ [acme@toolbox pahole]$ pahole --show_decl_info -F btf -C Alignment vmlinux.rust
> /* Used at: vmlinux.rust */
> /* <0> (null):0 */
> enum Alignment {
> Left = 0,
> Right = 1,
> Center = 2,
> Unknown = 3,
> } __attribute__((__packed__));
>
> ⬢ [acme@toolbox pahole]$
>
> I'll fixup those two:
>
> die__create_new_enumeration: DW_TAG_subprogram (0x2e) @ <0x4cb784b> not handled in a rust CU!
> tag__recode_dwarf_type: couldn't find name for function 0x4cd72bf, abstract_origin=0, specification=0x4cb784
>
> I.e. support functions inside enumerations.
>
> And sure this will be refused by the kernel, lots of stuff that have
> invalid names, probably need to turn those into void as well as a
> continuation of this hack, then prune, maybe that is it, we'll see.
>
> Going AFK now.
>
> - Arnaldo

Doing a little more digging, I've also found that the latest version
of `pahole` doesn't seem to conflict with LTO in my test builds - it
seems to successfully filter out the Rust types. Version 1.25 was
causing the errors that got reported to me and I was able to
reproduce.