Skip to content

Commit

Permalink
Make BPF symbolization tests end-to-end tests
Browse files Browse the repository at this point in the history
  • Loading branch information
d-e-s-o committed Oct 25, 2024
1 parent d7878ac commit 3c3a1eb
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 89 deletions.
8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,18 @@ zstd = ["dep:zstd"]
# Below here are dev-mostly features that should not be needed by
# regular users.

# Expose test-only helpers for convenient use in end-to-end tests from
# crate.
test = []
# Enable code paths requiring a nightly toolchain. This feature is only meant to
# be used for testing and benchmarking purposes, not for the core library, which
# is expected to work on stable.
nightly = []

[[test]]
name = "blazesym"
required-features = ["test"]

[[example]]
name = "addr2ln"

Expand All @@ -103,6 +110,7 @@ required-features = ["demangle", "blazesym-dev/generate-unit-test-files"]
[[bench]]
name = "main"
harness = false
required-features = ["test"]

[profile.release]
debug = true
Expand Down
45 changes: 45 additions & 0 deletions benches/symbolize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ use blazesym::symbolize::Input;
use blazesym::symbolize::Process;
use blazesym::symbolize::Source;
use blazesym::symbolize::Symbolizer;
#[cfg(target_os = "linux")]
use blazesym::test_helper::with_bpf_symbolization_target_addrs;
use blazesym::Addr;
use blazesym::Pid;

Expand Down Expand Up @@ -175,6 +177,47 @@ where
});
}

/// Benchmark the symbolization of BPF program kernel addresses.
#[cfg(target_os = "linux")]
fn symbolize_kernel_bpf_uncached<M>(b: &mut Bencher<'_, M>) {
with_bpf_symbolization_target_addrs(|handle_getpid, subprogram| {
let () = b.iter(|| {
let src = symbolize::Source::Kernel(symbolize::Kernel::default());
let symbolizer = Symbolizer::new();

let result = symbolizer
.symbolize(
&src,
symbolize::Input::AbsAddr(&[handle_getpid, subprogram]),
)
.unwrap();

assert_eq!(result.len(), 2);
});
});
}

/// Benchmark the symbolization of BPF program kernel addresses when
/// relevant data is readily cached.
#[cfg(target_os = "linux")]
fn symbolize_kernel_bpf_cached<M>(b: &mut Bencher<'_, M>) {
with_bpf_symbolization_target_addrs(|handle_getpid, subprogram| {
let src = symbolize::Source::Kernel(symbolize::Kernel::default());
let symbolizer = Symbolizer::new();

let () = b.iter(|| {
let result = symbolizer
.symbolize(
&src,
symbolize::Input::AbsAddr(&[handle_getpid, subprogram]),
)
.unwrap();

assert_eq!(result.len(), 2);
});
});
}


pub fn benchmark<M>(group: &mut BenchmarkGroup<'_, M>)
where
Expand All @@ -186,5 +229,7 @@ where
bench_fn!(group, symbolize_dwarf_no_lines);
bench_fn!(group, symbolize_dwarf);
bench_fn!(group, symbolize_gsym);
bench_fn!(group, symbolize_kernel_bpf_uncached);
bench_fn!(group, symbolize_kernel_bpf_cached);
bench_sub_fn!(group, symbolize_gsym_multi_no_setup);
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ pub mod normalize;
mod once;
mod pid;
pub mod symbolize;
#[cfg(test)]
#[cfg(any(test, feature = "test"))]
mod test_helper;
mod util;
#[cfg(feature = "apk")]
Expand Down
84 changes: 0 additions & 84 deletions src/symbolize/symbolizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1384,8 +1384,6 @@ mod tests {
use crate::symbolize;
use crate::symbolize::CodeInfo;
use crate::test_helper::find_the_answer_fn_in_zip;
#[cfg(target_os = "linux")]
use crate::test_helper::with_bpf_symbolization_target_addrs;


/// Exercise the `Debug` representation of various types.
Expand Down Expand Up @@ -1692,86 +1690,4 @@ mod tests {
let () = test(zip_error_dispatch);
let () = test(zip_delayed_error_dispatch);
}

/// Test symbolization of a kernel address inside a BPF program.
#[cfg(target_os = "linux")]
#[test]
fn symbolize_kernel_bpf_program() {
with_bpf_symbolization_target_addrs(|handle_getpid, subprogram| {
let src = symbolize::Source::Kernel(symbolize::Kernel::default());
let symbolizer = Symbolizer::new();
let result = symbolizer
.symbolize(
&src,
symbolize::Input::AbsAddr(&[handle_getpid, subprogram]),
)
.unwrap();
let handle_getpid_sym = result[0].as_sym().unwrap();
assert_eq!(handle_getpid_sym.name, "handle__getpid");
let code_info = handle_getpid_sym.code_info.as_ref().unwrap();
assert_eq!(code_info.dir, None);
assert_eq!(
Path::new(&code_info.file).file_name(),
Some(OsStr::new("getpid.bpf.c"))
);
assert_eq!(code_info.line, Some(33));
assert_ne!(code_info.column, None);

let subprogram_sym = result[1].as_sym().unwrap();
assert_eq!(subprogram_sym.name, "subprogram");
let code_info = subprogram_sym.code_info.as_ref().unwrap();
assert_eq!(code_info.dir, None);
assert_eq!(
Path::new(&code_info.file).file_name(),
Some(OsStr::new("getpid.bpf.c"))
);
assert_eq!(code_info.line, Some(15));
assert_ne!(code_info.column, None);
})
}

/// Benchmark the symbolization of BPF program kernel addresses.
#[cfg(target_os = "linux")]
#[cfg(feature = "nightly")]
#[bench]
fn bench_symbolize_kernel_bpf_uncached(b: &mut Bencher) {
with_bpf_symbolization_target_addrs(|handle_getpid, subprogram| {
let () = b.iter(|| {
let src = symbolize::Source::Kernel(symbolize::Kernel::default());
let symbolizer = Symbolizer::new();

let result = symbolizer
.symbolize(
&src,
symbolize::Input::AbsAddr(&[handle_getpid, subprogram]),
)
.unwrap();

assert_eq!(result.len(), 2);
});
});
}

/// Benchmark the symbolization of BPF program kernel addresses when
/// relevant data is readily cached.
#[cfg(target_os = "linux")]
#[cfg(feature = "nightly")]
#[bench]
fn bench_symbolize_kernel_bpf_cached(b: &mut Bencher) {
with_bpf_symbolization_target_addrs(|handle_getpid, subprogram| {
let src = symbolize::Source::Kernel(symbolize::Kernel::default());
let symbolizer = Symbolizer::new();

let () = b.iter(|| {
let result = symbolizer
.symbolize(
&src,
symbolize::Input::AbsAddr(&[handle_getpid, subprogram]),
)
.unwrap();

assert_eq!(result.len(), 2);
});
});
}
}
9 changes: 5 additions & 4 deletions src/test_helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,10 @@ mod bpf {
value.expect("did not receive RingBuffer callback")
}

/// Retrieve the address of the `symbolization_target` function in the
/// `getpid.bpf.o` BPF program.
pub(crate) fn with_bpf_symbolization_target_addrs<F>(f: F)
/// Retrieve the address of the `handle__getpid` and `subprogram`
/// functions in the `getpid.bpf.o` BPF program.
#[allow(dead_code)]
pub fn with_bpf_symbolization_target_addrs<F>(f: F)
where
F: FnOnce(Addr, Addr),
{
Expand All @@ -167,4 +168,4 @@ mod bpf {
}

#[cfg(target_os = "linux")]
pub(crate) use bpf::*;
pub use bpf::*;
39 changes: 39 additions & 0 deletions tests/blazesym.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ use blazesym::symbolize::Reason;
use blazesym::symbolize::Resolve;
use blazesym::symbolize::Symbolized;
use blazesym::symbolize::Symbolizer;
#[cfg(target_os = "linux")]
use blazesym::test_helper::with_bpf_symbolization_target_addrs;
use blazesym::Addr;
use blazesym::ErrorKind;
use blazesym::Pid;
Expand Down Expand Up @@ -805,6 +807,43 @@ fn symbolize_process_with_custom_dispatch() {
test(process_no_dispatch);
}

/// Test symbolization of a kernel address inside a BPF program.
#[cfg(target_os = "linux")]
#[test]
fn symbolize_kernel_bpf_program() {
with_bpf_symbolization_target_addrs(|handle_getpid, subprogram| {
let src = symbolize::Source::Kernel(symbolize::Kernel::default());
let symbolizer = Symbolizer::new();
let result = symbolizer
.symbolize(
&src,
symbolize::Input::AbsAddr(&[handle_getpid, subprogram]),
)
.unwrap();
let handle_getpid_sym = result[0].as_sym().unwrap();
assert_eq!(handle_getpid_sym.name, "handle__getpid");
let code_info = handle_getpid_sym.code_info.as_ref().unwrap();
assert_eq!(code_info.dir, None);
assert_eq!(
Path::new(&code_info.file).file_name(),
Some(OsStr::new("getpid.bpf.c"))
);
assert_eq!(code_info.line, Some(33));
assert_ne!(code_info.column, None);

let subprogram_sym = result[1].as_sym().unwrap();
assert_eq!(subprogram_sym.name, "subprogram");
let code_info = subprogram_sym.code_info.as_ref().unwrap();
assert_eq!(code_info.dir, None);
assert_eq!(
Path::new(&code_info.file).file_name(),
Some(OsStr::new("getpid.bpf.c"))
);
assert_eq!(code_info.line, Some(15));
assert_ne!(code_info.column, None);
})
}

/// Check that we can normalize addresses in an ELF shared object.
#[cfg(target_os = "linux")]
#[test]
Expand Down

0 comments on commit 3c3a1eb

Please sign in to comment.