[llvm] [BPF] Support for `DW_TAG_variant_part` in BTF generation (PR #155783)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Oct 6 09:45:38 PDT 2025
================
@@ -301,21 +303,61 @@ void BTFTypeStruct::completeType(BTFDebug &BDebug) {
BTFType.NameOff = BDebug.addString(STy->getName());
+ uint64_t InitialOffset = 0;
+ if (STy->getTag() == dwarf::DW_TAG_variant_part) {
+ // Variant parts have a discriminator, which has its own memory location at
+ // the beginning, and variants, which share the memory location afterwards.
+ // LLVM DI doesn't consider discriminator as an element and instead keeps
+ // it as a separate reference.
+ // To keep BTF simple, let's represent the structure as an union with
+ // discriminator as the first element and apply offsets to the other
+ // elements.
+ struct BTF::BTFMember Discriminator;
+ const auto *DDTy = STy->getDiscriminator();
+
+ InitialOffset += DDTy->getOffsetInBits() + DDTy->getSizeInBits();
----------------
eddyz87 wrote:
This initial offset computation is wrong. Consider the example below:
```
$ rustc --emit=llvm-ir -C debuginfo=full --crate-type=lib -o - test-debug-info.rs | llc --mtriple=bpfel -filetype=obj -o test.o && bpftool btf dump file test.o
[1] STRUCT 'Adt' size=12 vlen=1
'(anon)' type_id=2 bits_offset=0
[2] UNION '(anon)' size=12 vlen=3
'(anon)' type_id=4 bits_offset=0
'First' type_id=3 bits_offset=32 // <----------- offset 32 <------ cumulative offset 64
'Second' type_id=6 bits_offset=32 /
[3] STRUCT 'First' size=12 vlen=2 /
'a' type_id=4 bits_offset=32 // <-------------- offset 32 <----
'b' type_id=5 bits_offset=64
[...]
{llvm} [~/tmp]
$ rustc --emit=llvm-ir -C debuginfo=full --crate-type=lib -o - test-debug-info.rs | llc --mtriple=bpfel -filetype=obj -o - | llvm-dwarfdump -
[...]
0x0000003d: DW_TAG_structure_type
DW_AT_name ("Adt")
DW_AT_byte_size (0x0c)
DW_AT_accessibility (DW_ACCESS_public)
DW_AT_alignment (4)
DW_AT_accessibility (DW_ACCESS_public) DW_AT_alignment (4)
0x00000045: DW_TAG_variant_part
DW_AT_discr (0x0000004a)
0x0000004a: DW_TAG_member
DW_AT_type (0x000000b2 "u32")
DW_AT_alignment (4)
DW_AT_data_member_location (0x00)
DW_AT_artificial (true)
0x00000051: DW_TAG_variant
DW_AT_discr_value (0x00)
0x00000053: DW_TAG_member
DW_AT_name ("First")
DW_AT_type (0x0000006e "test_debug_info::Adt::First")
DW_AT_alignment (4)
DW_AT_data_member_location (0x00) <---------------------------- offset 0
0x0000005e: NULL
[...]
0x0000006e: DW_TAG_structure_type
DW_AT_name ("First")
DW_AT_byte_size (0x0c)
DW_AT_accessibility (DW_ACCESS_public)
DW_AT_alignment (4)
0x00000076: DW_TAG_member
DW_AT_name ("a")
DW_AT_type (0x000000b2 "u32")
DW_AT_alignment (4)
DW_AT_data_member_location (0x04) <--------------------------- offset 32
DW_AT_accessibility (DW_ACCESS_public)
[...]
```
Note how DWARF and BTF encode different offsets for field `a`.
To correctly handle initial offset, it has to be propagated into the types, referenced in variant part.
But this is complicated, error-prone, and tightly coupled with specifics of DWARF, produced by rust frontend (not guaranteed to be stable).
Let's just drop the initial offset computation and keep discriminant as is.
https://github.com/llvm/llvm-project/pull/155783
More information about the llvm-commits
mailing list