Skip to content

Commit 2dd9c13

Browse files
d-e-s-oinsearchoflosttime
authored andcommitted
libbpf-cargo: Strip DWARF information from generated object files
Clang generated BPF object files may contain DWARF information that references paths to temporary directories, for example. That ends up rendering our generated skeleton unstable, as it potentially changes between invocations [0]. That can be unfortunate if the skeleton is meant to be checked into version control. Andrii suggested [1] stripping said DWARF information by linking the object file, which strips it as a side effect. This change does so. [0] #163 [1] #169 (comment) Closes: #177 Signed-off-by: Daniel Müller <deso@posteo.net>
1 parent b9bce36 commit 2dd9c13

File tree

5 files changed

+80
-4
lines changed

5 files changed

+80
-4
lines changed

.github/workflows/rust.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,15 @@ jobs:
4444
override: true
4545
- name: Install deps
4646
run: |
47-
sudo apt-get install -y clang-14 libelf-dev zlib1g-dev
47+
sudo apt-get install -y clang-14 libelf-dev zlib1g-dev linux-headers-$(uname -r)
48+
sudo ln -s /usr/include/asm-generic /usr/include/asm
4849
sudo rm -f /bin/clang && sudo ln -s /usr/bin/clang-14 /bin/clang
4950
- uses: Swatinem/rust-cache@v2.2.0
5051
- name: Build
5152
run: cargo build --verbose --workspace --exclude runqslower
5253
- name: Run tests
5354
# Skip BTF tests which require sudo
54-
run: cargo test --verbose --workspace --exclude runqslower -- --skip test_object --skip test_tc
55+
run: cargo test --verbose --workspace --exclude runqslower -- --skip test_object --skip test_tc --include-ignored
5556
- name: Run BTF tests
5657
run: cd libbpf-rs && cargo test --verbose -- test_object test_tc
5758

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

libbpf-cargo/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ novendor = ["libbpf-sys/novendor"]
3333
anyhow = "1.0.1"
3434
cargo_metadata = "0.15.0"
3535
libbpf-sys = { version = "1.0.3" }
36+
libbpf-rs = { path = "../libbpf-rs" }
3637
memmap2 = "0.5"
3738
num_enum = "0.5"
3839
regex = { version = "1.6.0", default-features = false, features = ["std", "unicode-perl"] }

libbpf-cargo/src/build.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,25 @@ fn check_clang(debug: bool, clang: &Path, skip_version_checks: bool) -> Result<(
105105
Ok(())
106106
}
107107

108+
/// Strip DWARF information from the provided BPF object file.
109+
///
110+
/// We rely on the `libbpf` linker here, which removes debug information as a
111+
/// side-effect.
112+
fn strip_dwarf_info(file: &Path) -> Result<()> {
113+
let mut temp_file = file.as_os_str().to_os_string();
114+
temp_file.push(".tmp");
115+
116+
fs::rename(file, &temp_file).context("Failed to rename compiled BPF object file")?;
117+
118+
let mut linker =
119+
libbpf_rs::Linker::new(file).context("Failed to instantiate libbpf object file linker")?;
120+
linker
121+
.add(temp_file)
122+
.context("Failed to add object file to BPF linker")?;
123+
linker.link().context("Failed to link object file")?;
124+
Ok(())
125+
}
126+
108127
/// We're essentially going to run:
109128
///
110129
/// clang -g -O2 -target bpf -c -D__TARGET_ARCH_$(ARCH) runqslower.bpf.c -o runqslower.bpf.o
@@ -154,7 +173,11 @@ fn compile_one(debug: bool, source: &Path, out: &Path, clang: &Path, options: &s
154173
);
155174
}
156175

157-
Ok(())
176+
// Compilation with clang may contain DWARF information that references
177+
// system specific and temporary paths. That can render our generated
178+
// skeletons unstable, potentially rendering them unsuitable for inclusion
179+
// in version control systems. So strip this information.
180+
strip_dwarf_info(out).with_context(|| format!("Failed to strip object file {}", out.display()))
158181
}
159182

160183
fn compile(debug: bool, objs: &[UnprocessedObj], clang: &Path, target_dir: &Path) -> Result<()> {

libbpf-cargo/src/test.rs

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::{
22
convert::TryInto,
3-
fs::{create_dir, read, File, OpenOptions},
3+
fs::{create_dir, read, read_to_string, write, File, OpenOptions},
44
io::Write,
55
path::{Path, PathBuf},
66
process::Command,
@@ -918,6 +918,56 @@ fn test_skeleton_builder_arrays_ptrs() {
918918
assert!(status.success());
919919
}
920920

921+
/// Check that skeleton creation is deterministic, i.e., that no temporary paths
922+
/// change the output between invocations.
923+
#[test]
924+
#[ignore = "may fail on some systems; depends on kernel headers that have been seen to be broken"]
925+
fn test_skeleton_builder_deterministic() {
926+
let (_dir, proj_dir, _cargo_toml) = setup_temp_project();
927+
928+
create_dir(proj_dir.join("src/bpf")).expect("failed to create prog dir");
929+
write(
930+
proj_dir.join("src/bpf/prog.bpf.c"),
931+
r#"
932+
#include <linux/bpf.h>
933+
#include <bpf/bpf_helpers.h>
934+
935+
struct {
936+
__uint(type, BPF_MAP_TYPE_REUSEPORT_SOCKARRAY);
937+
} sock_map SEC(".maps");
938+
939+
SEC("sk_reuseport/reuse_pass")
940+
long prog_select_sk(struct sk_reuseport_md *reuse_md)
941+
{
942+
unsigned int index = 0;
943+
bpf_sk_select_reuseport(reuse_md, &sock_map, &index, 0);
944+
return SK_PASS;
945+
}
946+
"#,
947+
)
948+
.expect("failed to write prog.bpf.c");
949+
950+
let skel1 = NamedTempFile::new().unwrap();
951+
SkeletonBuilder::new()
952+
.source(proj_dir.join("src/bpf/prog.bpf.c"))
953+
.debug(true)
954+
.clang("clang")
955+
.build_and_generate(skel1.path())
956+
.unwrap();
957+
let skel1 = read_to_string(skel1.path()).unwrap();
958+
959+
let skel2 = NamedTempFile::new().unwrap();
960+
SkeletonBuilder::new()
961+
.source(proj_dir.join("src/bpf/prog.bpf.c"))
962+
.debug(true)
963+
.clang("clang")
964+
.build_and_generate(skel2.path())
965+
.unwrap();
966+
let skel2 = read_to_string(skel2.path()).unwrap();
967+
968+
assert_eq!(skel1, skel2);
969+
}
970+
921971
// -- TEST RUST GENERATION OF BTF PROGRAMS --
922972

923973
/// Searches the Btf struct for a BtfType

0 commit comments

Comments
 (0)