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

Arnaldo Carvalho de Melo
2025-01-09T22:39:27Z

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