btf_types.rs 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. use std::{io, path::Path, process::Command, str::from_utf8};
  2. use thiserror::Error;
  3. use crate::bindgen;
  4. #[derive(Error, Debug)]
  5. pub enum Error {
  6. #[error("error executing bpftool")]
  7. BpfTool(#[source] io::Error),
  8. #[error("{stderr}\nbpftool failed with exit code {code}")]
  9. BpfToolExit { code: i32, stderr: String },
  10. #[error("bindgen failed")]
  11. Bindgen,
  12. #[error("rustfmt failed")]
  13. Rustfmt(#[source] io::Error),
  14. }
  15. pub fn generate<T: AsRef<str>>(btf_file: &Path, types: &[T]) -> Result<String, Error> {
  16. let mut bindgen = bindgen::bpf_builder();
  17. let c_header = c_header_from_btf(btf_file)?;
  18. bindgen = bindgen.header_contents("kernel_types.h", &c_header);
  19. for ty in types {
  20. bindgen = bindgen.allowlist_type(ty);
  21. }
  22. let bindings = bindgen.generate().or(Err(Error::Bindgen))?.to_string();
  23. Ok(bindings)
  24. }
  25. fn c_header_from_btf(path: &Path) -> Result<String, Error> {
  26. let output = Command::new("bpftool")
  27. .args(&["btf", "dump", "file"])
  28. .arg(path)
  29. .args(&["format", "c"])
  30. .output()
  31. .map_err(Error::BpfTool)?;
  32. if !output.status.success() {
  33. return Err(Error::BpfToolExit {
  34. code: output.status.code().unwrap(),
  35. stderr: from_utf8(&output.stderr).unwrap().to_owned(),
  36. });
  37. }
  38. Ok(from_utf8(&output.stdout).unwrap().to_owned())
  39. }