diff --git a/libbpf-cargo/CHANGELOG.md b/libbpf-cargo/CHANGELOG.md
index 3766ef4e..352da7b5 100644
--- a/libbpf-cargo/CHANGELOG.md
+++ b/libbpf-cargo/CHANGELOG.md
@@ -1,3 +1,8 @@
+Unreleased
+----------
+- Fixed skeleton generation when `enum64` types are present
+
+
0.25.0-beta.0
-------------
- Represent C enums with custom types and const fields
diff --git a/libbpf-cargo/src/gen/btf.rs b/libbpf-cargo/src/gen/btf.rs
index b8b76d45..3f3bcbab 100644
--- a/libbpf-cargo/src/gen/btf.rs
+++ b/libbpf-cargo/src/gen/btf.rs
@@ -31,6 +31,93 @@ use super::InternalMapType;
const ANON_PREFIX: &str = "__anon_";
+
+#[derive(Clone, Debug)]
+pub(crate) enum Either {
+ A(A),
+ B(B),
+}
+
+impl Iterator for Either
+where
+ A: Iterator- ,
+ B: Iterator
- ,
+{
+ type Item = T;
+
+ fn next(&mut self) -> Option {
+ match self {
+ Self::A(a) => a.next(),
+ Self::B(b) => b.next(),
+ }
+ }
+}
+
+impl ExactSizeIterator for Either
+where
+ A: ExactSizeIterator
- ,
+ B: ExactSizeIterator
- ,
+{
+}
+
+
+/// Convert an `EnumMember` into a `Enum64Member`.
+fn enum64_member_from_enum_member(other: types::EnumMember<'_>) -> types::Enum64Member<'_> {
+ types::Enum64Member {
+ name: other.name,
+ value: other.value.into(),
+ }
+}
+
+
+type EitherEnum<'btf> = Either, types::Enum64<'btf>>;
+
+impl EitherEnum<'_> {
+ fn size(&self) -> usize {
+ match self {
+ Self::A(t) => t.size(),
+ Self::B(t) => t.size(),
+ }
+ }
+
+ fn is_signed(&self) -> bool {
+ match self {
+ Self::A(t) => t.is_signed(),
+ Self::B(t) => t.is_signed(),
+ }
+ }
+
+ fn iter(&self) -> impl ExactSizeIterator
- > {
+ match self {
+ Self::A(t) => Either::A(t.iter().map(enum64_member_from_enum_member)),
+ Self::B(t) => Either::B(t.iter()),
+ }
+ }
+}
+
+impl<'btf> From> for EitherEnum<'btf> {
+ fn from(other: types::Enum<'btf>) -> Self {
+ Self::A(other)
+ }
+}
+
+impl<'btf> From> for EitherEnum<'btf> {
+ fn from(other: types::Enum64<'btf>) -> Self {
+ Self::B(other)
+ }
+}
+
+impl<'btf> Deref for EitherEnum<'btf> {
+ type Target = BtfType<'btf>;
+
+ fn deref(&self) -> &Self::Target {
+ match self {
+ Self::A(t) => t,
+ Self::B(t) => t,
+ }
+ }
+}
+
/// Check whether the provided type is "unsafe" to use.
///
/// A type is considered unsafe by this function if it is not valid for
@@ -439,7 +526,8 @@ impl StructOps {{
.type_definition_for_composites(def, &mut self.deps, t)?
}
}
- BtfKind::Enum(t) => self.btf.type_definition_for_enums(def, t)?,
+ BtfKind::Enum(t) => self.btf.type_definition_for_enums(def, t.into())?,
+ BtfKind::Enum64(t) => self.btf.type_definition_for_enums(def, t.into())?,
_ => bail!("Invalid type: {:?}", ty.kind()),
});
}
@@ -548,7 +636,8 @@ impl<'s> GenBtf<'s> {
btf_type_match!(match ty {
BtfKind::Composite(t) =>
self.type_definition_for_composites(&mut def, &mut dependent_types, t)?,
- BtfKind::Enum(t) => self.type_definition_for_enums(&mut def, t)?,
+ BtfKind::Enum(t) => self.type_definition_for_enums(&mut def, t.into())?,
+ BtfKind::Enum64(t) => self.type_definition_for_enums(&mut def, t.into())?,
BtfKind::DataSec(t) =>
self.type_definition_for_datasec(&mut def, &mut dependent_types, t)?,
_ => bail!("Invalid type: {:?}", ty.kind()),
@@ -786,7 +875,7 @@ impl<'s> GenBtf<'s> {
Ok(())
}
- fn type_definition_for_enums(&self, def: &mut String, t: types::Enum<'_>) -> Result<()> {
+ fn type_definition_for_enums(&self, def: &mut String, t: EitherEnum<'_>) -> Result<()> {
let repr_size = match t.size() {
1 => "8",
2 => "16",
diff --git a/libbpf-cargo/src/test.rs b/libbpf-cargo/src/test.rs
index 8003f3a5..0443aada 100644
--- a/libbpf-cargo/src/test.rs
+++ b/libbpf-cargo/src/test.rs
@@ -1947,6 +1947,94 @@ impl Default for Foo {
assert_definition(&btf, &struct_bar, expected_output);
}
+#[test]
+fn test_btf_dump_definition_enum64() {
+ let prog_text = r#"
+#include "vmlinux.h"
+#include
+
+enum Foo {
+ Zero = 0,
+ Infinite = 0xffffffffffffffff,
+};
+
+struct Bar {
+ enum Foo foo;
+};
+struct Bar bar;
+"#;
+
+ let expected_output = r#"
+#[derive(Debug, Default, Copy, Clone)]
+#[repr(C)]
+pub struct Bar {
+ pub foo: Foo,
+}
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+#[repr(transparent)]
+pub struct Foo(pub u64);
+#[allow(non_upper_case_globals)]
+impl Foo {
+ pub const Zero: Foo = Foo(0);
+ pub const Infinite: Foo = Foo(18446744073709551615);
+}
+impl Default for Foo {
+ fn default() -> Self { Foo::Zero }
+}
+"#;
+
+ let mmap = build_btf_mmap(prog_text);
+ let btf = btf_from_mmap(&mmap);
+
+ // Find our struct
+ let struct_bar = find_type_in_btf!(btf, types::Struct<'_>, "Bar");
+ assert_definition(&btf, &struct_bar, expected_output);
+}
+
+#[test]
+fn test_btf_dump_definition_enum64_signed() {
+ let prog_text = r#"
+#include "vmlinux.h"
+#include
+
+enum Foo {
+ Zero = 0,
+ Whatevs = -922337854775808,
+};
+
+struct Bar {
+ enum Foo foo;
+};
+struct Bar bar;
+"#;
+
+ let expected_output = r#"
+#[derive(Debug, Default, Copy, Clone)]
+#[repr(C)]
+pub struct Bar {
+ pub foo: Foo,
+}
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+#[repr(transparent)]
+pub struct Foo(pub i64);
+#[allow(non_upper_case_globals)]
+impl Foo {
+ pub const Zero: Foo = Foo(0);
+ pub const Whatevs: Foo = Foo(-922337854775808);
+}
+impl Default for Foo {
+ fn default() -> Self { Foo::Zero }
+}
+"#;
+
+ let mmap = build_btf_mmap(prog_text);
+ let btf = btf_from_mmap(&mmap);
+
+ // Find our struct
+ let struct_bar = find_type_in_btf!(btf, types::Struct<'_>, "Bar");
+ assert_definition(&btf, &struct_bar, expected_output);
+}
+
#[test]
fn test_btf_dump_definition_union() {
let prog_text = r#"
diff --git a/libbpf-rs/src/btf/types.rs b/libbpf-rs/src/btf/types.rs
index bf22458c..b87cd368 100644
--- a/libbpf-rs/src/btf/types.rs
+++ b/libbpf-rs/src/btf/types.rs
@@ -852,6 +852,15 @@ gen_collection_concrete_type! {
}
}
+impl Enum64<'_> {
+ /// Check whether the enum is signed or not.
+ #[inline]
+ pub fn is_signed(&self) -> bool {
+ self.kind_flag()
+ }
+}
+
+
/// A macro that allows matching on the type of a [`BtfType`] as if it was an enum.
///
/// Each pattern can be of two types.