[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