From 63a43b2ad78c14db78361c25026018bef7b8c52c Mon Sep 17 00:00:00 2001 From: Huang-Huang Bao Date: Mon, 9 Dec 2024 13:49:04 +0800 Subject: [PATCH] improve: allow using bpftool for stripping Also skip stripping if failed. Add env EINAT_BPF_STRIP_CMD to force stripping command used. --- README.md | 13 +++++----- build.rs | 60 ++++++++++++++++++++++++++++++++++++++------- docs/guide/cross.md | 7 +++++- 3 files changed, 64 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index c364c6b..a4bd5d8 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ For implementation details, see documentations under [reference](./docs/referenc - Linux kernel >= 5.15 (compiled with BPF and BTF support) on target machine - Rust toolchain (`cargo` etc.) - `clang` for compiling BPF C code -- `llvm-strip` for stripping compiled BPF object +- `bpftool` or `llvm-strip` for stripping compiled BPF object - `libbpf` headers - (optional) `pkg-config` to locate `libbpf` headers @@ -30,7 +30,7 @@ Additional dependencies for `"libbpf"` loader: - `rustfmt` for formatting generated code - `clang` libs for bindgen -- `libelf` from elfutils and `zlib` on target platform +- `libelf` from elfutils and `zlib` on target platform Currently we support `"aya"`, `"libbpf"` and `"libbpf-skel"` eBPF loaders, only the `"aya"` is enabled by default as it requires no native dependencies on target platform except libc. @@ -65,10 +65,11 @@ See also [cross-compilation guide](./docs/guide/cross.md) for cross-compilation ### Build Environment Variables -| Name | Example Value | Note | -| ---------------------- | -------------------------- | ----------------------------------------------- | -| `EINAT_BPF_CFLAGS` | `-I/usr/include/` | Specify extra CFLAGS for BPF object compilation | -| `LIBBPF_NO_PKG_CONFIG` | `1` | Disable [pkg_config lookup] of libbpf. | +| Name | Example Value | Note | +| ---------------------- | -------------------------- | --------------------------------------------------------------------------- | +| `EINAT_BPF_CFLAGS` | `-I/usr/include/` | Specify extra CFLAGS for BPF object compilation | +| `EINAT_BPF_STRIP_CMD` | `llvm-strip -g -o` | BPF object stripping command, would followed by target path and source path | +| `LIBBPF_NO_PKG_CONFIG` | `1` | Disable [pkg_config lookup] of libbpf. | [pkg_config lookup]: https://docs.rs/pkg-config/0.3.31/pkg_config/index.html#environment-variables diff --git a/build.rs b/build.rs index e35776a..680621a 100644 --- a/build.rs +++ b/build.rs @@ -33,8 +33,10 @@ fn c_args() -> Vec { #[cfg(any(feature = "aya", feature = "libbpf"))] fn einat_obj_build() { + use std::ffi::OsStr; use std::process::Command; + let bpf_obj_tmp = &out_path("einat.bpf.tmp.o"); let bpf_obj = &out_path("einat.bpf.o"); // compile BPF C code @@ -79,22 +81,60 @@ fn einat_obj_build() { .arg("-c") .arg(SRC) .arg("-o") - .arg(bpf_obj) + .arg(bpf_obj_tmp) .status() .expect("compile BPF object failed"); if !res.success() { panic!("{}", res); } - // strip the DWARF debug information - let res = Command::new("llvm-strip") - .arg("--strip-debug") - .arg(bpf_obj) - .status() - .expect("llvm-strip BPF object file failed"); - if !res.success() { - panic!("{}", res); + fn strip_obj>(strip_cmd: &str, target: S, source: S) -> Result<(), String> { + let mut args = strip_cmd.split_ascii_whitespace(); + let cmd = args.next().unwrap(); + let res = Command::new(cmd) + .args(args) + .arg(target) + .arg(source) + .status(); + + match res { + Ok(res) => { + if res.success() { + return Ok(()); + } + Err(format!("{}: {}", strip_cmd, res)) + } + Err(err) => Err(format!("{}: {}", strip_cmd, err)), + } } + + // strip the DWARF debug information + let strip_bpf_obj = || -> Result<(), String> { + if let Some(strip_cmd) = option_env!("EINAT_BPF_STRIP_CMD") { + return strip_obj(strip_cmd, bpf_obj, bpf_obj_tmp); + } + + let res = strip_obj("bpftool gen object", bpf_obj, bpf_obj_tmp); + if res.is_ok() { + return res; + } + eprintln!("strip with bpftool failed, fallback to llvm-strip"); + + let res = strip_obj("llvm-strip -g -o", bpf_obj, bpf_obj_tmp); + if res.is_ok() { + return res; + } + eprintln!("strip with llvm-strip failed, skip stripping"); + + std::fs::rename(bpf_obj_tmp, bpf_obj).unwrap(); + + Ok(()) + }; + + strip_bpf_obj().expect("strip BPF object file failed"); + + println!("cargo:rerun-if-env-changed=EINAT_BPF_CFLAGS"); + println!("cargo:rerun-if-env-changed=EINAT_BPF_STRIP_CMD"); } #[cfg(feature = "libbpf-skel")] @@ -120,4 +160,6 @@ fn main() { println!("cargo:rerun-if-changed={}", SRC_DIR); println!("cargo:rerun-if-changed=build.rs"); + + println!("cargo:rerun-if-changed=/null"); } diff --git a/docs/guide/cross.md b/docs/guide/cross.md index ee30ee5..96a2a0f 100644 --- a/docs/guide/cross.md +++ b/docs/guide/cross.md @@ -10,7 +10,11 @@ To enable only the "libbpf" loader, specify Cargo flags `--no-default-features - Install `gcc-aarch64-linux-gnu` for cross linking. Install `clang` for bindgen and compile eBPF C code in this project. ``` -apt install gcc-aarch64-linux-gnu clang llvm +apt install gcc-aarch64-linux-gnu clang +# bpftool for BPF object stripping +apt install linux-tools-common +# Or use llvm-strip +apt install llvm ``` Install `rustup` to get Rust>=1.74, see https://www.rust-lang.org/tools/install. Also make sure `rustfmt` is installed as it's used by `libbpf-cargo`. @@ -47,6 +51,7 @@ export CFLAGS_aarch64_unknown_linux_gnu="-I /usr/include/aarch64-linux-gnu -L /u ``` Specify `EINAT_BPF_CFLAGS` if einat build script failed to locate libbpf headers. + ``` export EINAT_BPF_CFLAGS="-I /usr/include/aarch64-linux-gnu" ```