diff --git a/libbpf-cargo/src/gen/btf.rs b/libbpf-cargo/src/gen/btf.rs index 0f649fd7..9d609d6b 100644 --- a/libbpf-cargo/src/gen/btf.rs +++ b/libbpf-cargo/src/gen/btf.rs @@ -175,12 +175,12 @@ impl<'s> GenBtf<'s> { } BtfKind::Struct | BtfKind::Union | BtfKind::Enum | BtfKind::Enum64 => self.get_type_name_handling_anon_types(&ty).into_owned(), - // The only way a variable references a function is through a function pointer. - // Return c_void here so the final def will look like `*mut c_void`. + // The only way a variable references a function or forward declaration is through a + // pointer. Return c_void here so the final def will look like `*mut c_void`. // // It's not like rust code can call a function inside a bpf prog either so we don't // really need a full definition. `void *` is totally sufficient for sharing a pointer. - BtfKind::Func | BtfKind::FuncProto => "std::ffi::c_void".to_string(), + BtfKind::Fwd | BtfKind::Func | BtfKind::FuncProto => "std::ffi::c_void".to_string(), BtfKind::Var(t) => self.type_declaration(t.referenced_type())?, _ => bail!("Invalid type: {ty:?}"), }); diff --git a/libbpf-cargo/src/test.rs b/libbpf-cargo/src/test.rs index 43337d84..f5e8621d 100644 --- a/libbpf-cargo/src/test.rs +++ b/libbpf-cargo/src/test.rs @@ -1402,6 +1402,27 @@ impl Default for Foo { assert_definition(&btf, &struct_foo, expected_output); } +#[test] +fn test_btf_dump_fwd() { + let prog_text = r#" +#include "vmlinux.h" +#include + +struct sometypethatdoesnotexist *m; +"#; + + let mmap = build_btf_mmap(prog_text); + let btf = btf_from_mmap(&mmap); + + let m = find_type_in_btf!(btf, types::Var<'_>, "m"); + + assert_eq!( + "*mut std::ffi::c_void", + btf.type_declaration(*m) + .expect("Failed to generate foo decl") + ); +} + #[test] fn test_btf_dump_align() { let prog_text = r#"