Skip to content

Commit 3d49a82

Browse files
d-e-s-odanielocfb
authored andcommitted
libbpf-cargo: Add support for struct_ops shadow objects
This change adds support for struct_ops shadow objects to the generated skeletons. These allow for the pre-load modifications of fields in a struct_ops object. To make that happen we add a new generated struct_ops type that holds pointers to all the known struct_ops objects and allows for modification of their values before final load. Signed-off-by: Daniel Müller <[email protected]>
1 parent 1ba963c commit 3d49a82

File tree

3 files changed

+257
-21
lines changed

3 files changed

+257
-21
lines changed

libbpf-cargo/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ Unreleased
22
----------
33
- Removed `novendor` feature in favor of having disableable default
44
feature
5+
- Added support for `struct_ops` shadow objects for generated skeletons
56
- Adjusted `SkeletonBuilder::clang_args` to accept an iterator of
67
arguments instead of a string
78
- Added `--clang-args` argument to `make` and `build` sub-commands

libbpf-cargo/src/gen/btf.rs

Lines changed: 141 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ use libbpf_rs::Btf;
2222
use libbpf_rs::HasSize;
2323
use libbpf_rs::ReferencesType;
2424

25+
use super::canonicalize_internal_map_name;
26+
use super::InternalMapType;
27+
2528
const ANON_PREFIX: &str = "__anon_";
2629

2730
/// Check whether the provided type is "unsafe" to use.
@@ -377,11 +380,148 @@ impl<'s> GenBtf<'s> {
377380
Ok(def)
378381
}
379382

383+
pub fn struct_ops_type_definition(&self, processed: &mut HashSet<TypeId>) -> Result<String> {
384+
let mut def = String::new();
385+
let mut dependent_types = vec![];
386+
let mut vars = vec![];
387+
388+
// Take all the struct_ops datasec entries and collect their variables
389+
// (and dependent types).
390+
for ty in self.type_by_kind::<types::DataSec<'_>>() {
391+
let name = match ty.name() {
392+
Some(s) => s.to_str()?,
393+
None => "",
394+
};
395+
396+
if !matches!(
397+
canonicalize_internal_map_name(name),
398+
Some(InternalMapType::StructOps)
399+
) {
400+
continue;
401+
}
402+
403+
for var in ty.iter() {
404+
let var = self
405+
.type_by_id::<types::Var<'_>>(var.ty)
406+
.ok_or_else(|| anyhow!("datasec type does not point to a variable"))?;
407+
408+
if var.linkage() == types::Linkage::Static {
409+
// do not output Static Var
410+
continue;
411+
}
412+
413+
let () = vars.push(*var);
414+
415+
if let Some(next_ty) = next_type(*var)? {
416+
let () = dependent_types.push(next_ty);
417+
}
418+
}
419+
}
420+
421+
// Emit a single struct_ops definition containing all variables
422+
// discovered earlier.
423+
write!(
424+
def,
425+
r#"
426+
#[derive(Debug, Clone)]
427+
#[repr(C)]
428+
pub struct struct_ops {{
429+
"#
430+
)?;
431+
432+
for var in vars.iter() {
433+
writeln!(
434+
def,
435+
r#" pub {var_name}: *mut {var_type},"#,
436+
var_name = var.name().unwrap().to_string_lossy(),
437+
var_type = self.type_declaration(*var)?
438+
)?;
439+
}
440+
441+
writeln!(def, "}}")?;
442+
443+
write!(
444+
def,
445+
r#"
446+
impl struct_ops {{
447+
"#
448+
)?;
449+
450+
for var in vars.iter() {
451+
write!(
452+
def,
453+
r#"
454+
pub fn {var_name}(&self) -> &{var_type} {{
455+
// SAFETY: The library ensures that the member is pointing to
456+
// valid data.
457+
unsafe {{ self.{var_name}.as_ref() }}.unwrap()
458+
}}
459+
460+
pub fn {var_name}_mut(&mut self) -> &mut {var_type} {{
461+
// SAFETY: The library ensures that the member is pointing to
462+
// valid data.
463+
unsafe {{ self.{var_name}.as_mut() }}.unwrap()
464+
}}
465+
"#,
466+
var_name = var.name().unwrap().to_string_lossy(),
467+
var_type = self.type_declaration(*var)?
468+
)?;
469+
}
470+
471+
writeln!(def, "}}")?;
472+
473+
let vars = vars
474+
.into_iter()
475+
.map(|ty| ty.next_type().unwrap().type_id())
476+
.collect::<HashSet<_>>();
477+
478+
while !dependent_types.is_empty() {
479+
let ty = dependent_types.remove(0);
480+
if !processed.insert(ty.type_id()) {
481+
continue;
482+
}
483+
484+
btf_type_match!(match ty {
485+
BtfKind::Composite(t) => {
486+
if vars.contains(&ty.type_id()) {
487+
let opts = TypeDeclOpts {
488+
func_type: "libbpf_rs::libbpf_sys::bpf_program",
489+
};
490+
self.type_definition_for_composites_with_opts(
491+
&mut def,
492+
&mut dependent_types,
493+
t,
494+
&opts,
495+
)?
496+
} else {
497+
self.type_definition_for_composites(&mut def, &mut dependent_types, t)?
498+
}
499+
}
500+
BtfKind::Enum(t) => self.type_definition_for_enums(&mut def, t)?,
501+
_ => bail!("Invalid type: {:?}", ty.kind()),
502+
});
503+
}
504+
505+
Ok(def)
506+
}
380507
fn type_definition_for_composites<'a>(
381508
&'a self,
382509
def: &mut String,
383510
dependent_types: &mut Vec<BtfType<'a>>,
384511
t: types::Composite<'_>,
512+
) -> Result<()> {
513+
let opts = TypeDeclOpts {
514+
func_type: "std::ffi::c_void",
515+
};
516+
self.type_definition_for_composites_with_opts(def, dependent_types, t, &opts)
517+
}
518+
519+
fn type_definition_for_composites_with_opts<'a>(
520+
&'a self,
521+
def: &mut String,
522+
dependent_types: &mut Vec<BtfType<'a>>,
523+
t: types::Composite<'_>,
524+
opts: &TypeDeclOpts,
385525
) -> Result<()> {
386526
let packed = is_struct_packed(&t, &self.btf)?;
387527

@@ -476,7 +616,7 @@ impl<'s> GenBtf<'s> {
476616
// Set `offset` to end of current var
477617
offset = (member_offset / 8) as usize + size_of_type(field_ty, &self.btf)?;
478618

479-
let field_ty_str = self.type_declaration(field_ty)?;
619+
let field_ty_str = type_declaration_impl(field_ty, &self.anon_types, opts)?;
480620
let field_ty_str = if is_unsafe(field_ty) {
481621
Cow::Owned(format!("std::mem::MaybeUninit<{field_ty_str}>"))
482622
} else {

0 commit comments

Comments
 (0)