Skip to content

Commit f13b71a

Browse files
committed
[BPF] Handle nested wrapper structs in BPF map definition traversal
In Aya/Rust, BPF map definitions are nested in two nested types: * A struct representing the map type (e.g., `HashMap`, `RingBuf`) that provides methods for interacting with the map type (e.g. `HashMap::get`, `RingBuf::reserve`). * An `UnsafeCell`, which informs the Rust compiler that the type is thread-safe and can be safely mutated even as a global variable. The kernel guarantees map operation safety. This leads to a type hierarchy like: ```rust pub struct HashMap<K, V, const M: usize, const F: usize = 0>( core::cell::UnsafeCell<HashMapDef<K, V, M, F>>, ); const BPF_MAP_TYPE_HASH: usize = 1; pub struct HashMapDef<K, V, const M: usize, const F: usize = 0> { r#type: *const [i32; BPF_MAP_TYPE_HASH], key: *const K, value: *const V, max_entries: *const [i32; M], map_flags: *const [i32; F], } ``` Then used in the BPF program code as a global variable: ```rust #[unsafe(link_section = ".maps")] #[unsafe(export_name = "HASH_MAP")] static HASH_MAP: HashMap<u32, u32, 1337> = HashMap::new(); ``` Which is an equivalent of the following BPF map definition in C: ```c #define BPF_MAP_TYPE_HASH 1 struct { int (*type)[BPF_MAP_TYPE_HASH]; typeof(int) *key; typeof(int) *value; int (*max_entries)[1337]; } map_1 __attribute__((section(".maps"))); ``` Accessing the actual map definition requires traversing: ``` HASH_MAP -> __0 -> value ``` Previously, the BPF backend only visited the pointee types of the outermost struct, and didn’t descend into inner wrappers. This caused issues when the key/value types were custom structs: ```rust // Define custom structs for key and values. pub struct MyKey(u32); pub struct MyValue(u32); #[unsafe(link_section = ".maps")] #[unsafe(export_name = "HASH_MAP")] pub static HASH_MAP: HashMap<MyKey, MyValue, 1337> = HashMap::new(); ``` These types weren’t fully visited and appeared in BTF as forward declarations: ``` #30: <FWD> 'MyKey' kind:struct #31: <FWD> 'MyValue' kind:struct ``` The fix is to enhance `visitMapDefType` to recursively visit inner composite members. If a member is a composite type (likely a wrapper), it is now also visited using `visitMapDefType`, ensuring that the pointee types of the innermost stuct members, like `MyKey` and `MyValue`, are fully resolved in BTF. With this fix, the correct BTF entries are emitted: ``` #6: <STRUCT> 'MyKey' sz:4 n:1 #00 '__0' off:0 --> [7] #7: <INT> 'u32' bits:32 off:0 #8: <PTR> --> [9] #9: <STRUCT> 'MyValue' sz:4 n:1 #00 '__0' off:0 --> [7] ``` Fixes: #143361
1 parent bc36b44 commit f13b71a

File tree

2 files changed

+396
-2
lines changed

2 files changed

+396
-2
lines changed

llvm/lib/Target/BPF/BTFDebug.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -976,11 +976,24 @@ void BTFDebug::visitMapDefType(const DIType *Ty, uint32_t &TypeId) {
976976
if (Tag != dwarf::DW_TAG_structure_type || CTy->isForwardDecl())
977977
return;
978978

979-
// Visit all struct members to ensure pointee type is visited
979+
// Visit all struct members to ensure their types are visited.
980980
const DINodeArray Elements = CTy->getElements();
981981
for (const auto *Element : Elements) {
982982
const auto *MemberType = cast<DIDerivedType>(Element);
983-
visitTypeEntry(MemberType->getBaseType());
983+
const DIType *MemberBaseType = MemberType->getBaseType();
984+
985+
// If the member is a composite type, that may indicate the currently
986+
// visited composite type is a wrapper, and the member represents the
987+
// actual map definition.
988+
// In that case, visit the member with `visitMapDefType` instead of
989+
// `visitTypeEntry`, treating it specifically as a map definition rather
990+
// than as a regular composite type.
991+
const auto *MemberCTy = dyn_cast<DICompositeType>(MemberBaseType);
992+
if (MemberCTy) {
993+
visitMapDefType(MemberBaseType, TypeId);
994+
} else {
995+
visitTypeEntry(MemberBaseType);
996+
}
984997
}
985998

986999
// Visit this type, struct or a const/typedef/volatile/restrict type

0 commit comments

Comments
 (0)