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.