Skip to content

Commit

Permalink
Introduce Symbolizer::symbolize_single
Browse files Browse the repository at this point in the history
This change introduces a new API, Symbolizer::symbolize_single, that can
be used to symbolize a single address. Our "batch processing" is
somewhat cumbersome to use when it is clear that only a single input
address is available. On top of that, we can avoid the need for
dynamic memory allocation in that case, because we know that at most one
symbol can be returned.

Closes: #317

Signed-off-by: Daniel Müller <[email protected]>
  • Loading branch information
d-e-s-o committed Sep 20, 2023
1 parent 193242a commit e672676
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 16 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ Unreleased
- Added support for reporting inlined functions for Gsym format
- "Flattened" return type of `symbolize::Symbolizer::symbolize` method from
nested `Vec` to a single level `Vec`
- Introduced `symbolize::Symbolizer::symbolize_single` for more convenient
symbolization of a single address
- Added `size` member and `to_path` helper to `symbolize::Sym` type


Expand Down
45 changes: 45 additions & 0 deletions src/symbolize/symbolizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,51 @@ impl Symbolizer {
}
}
}

/// Symbolize a single address.
///
/// In general, it is more performant to symbolize addresses in batches
/// using [`symbolize`][Self::symbolize]. However, in cases where only a
/// single address is available, this method provides a more convenient API.
#[cfg_attr(feature = "tracing", crate::log::instrument(skip_all, fields(src = ?src, addr = format_args!("{addr:#x?}"))))]
pub fn symbolize_single(&self, src: &Source, addr: Addr) -> Result<Option<Sym>> {
match src {
Source::Elf(Elf {
path,
_non_exhaustive: (),
}) => {
let backend = self.elf_cache.find(path)?;
let resolver = ElfResolver::with_backend(path, backend)?;
self.symbolize_with_resolver(addr, &resolver)
}
Source::Kernel(kernel) => {
let resolver = self.create_kernel_resolver(kernel)?;
self.symbolize_with_resolver(addr, &resolver)
}
Source::Process(Process {
pid,
_non_exhaustive: (),
}) => {
let mut symbols = self.symbolize_user_addrs(&[addr], *pid)?;
debug_assert!(symbols.len() <= 1, "{symbols:#?}");
Ok(symbols.pop().map(|(sym, _idx)| sym))
}
Source::Gsym(Gsym::Data(GsymData {
data,
_non_exhaustive: (),
})) => {
let resolver = GsymResolver::with_data(data)?;
self.symbolize_with_resolver(addr, &resolver)
}
Source::Gsym(Gsym::File(GsymFile {
path,
_non_exhaustive: (),
})) => {
let resolver = GsymResolver::new(path.clone())?;
self.symbolize_with_resolver(addr, &resolver)
}
}
}
}

impl Default for Symbolizer {
Expand Down
33 changes: 17 additions & 16 deletions tests/blazesym.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,11 @@ fn find_function_size(name: &str, elf: &Path) -> usize {
fn symbolize_elf_dwarf_gsym() {
fn test(src: symbolize::Source, has_src_loc: bool) {
let symbolizer = Symbolizer::new();
let results = symbolizer
.symbolize(&src, &[0x2000100])
let result = symbolizer
.symbolize_single(&src, 0x2000100)
.unwrap()
.into_iter()
.collect::<Vec<_>>();
assert_eq!(results.len(), 1);
.unwrap();

let (result, _addr_idx) = &results[0];
assert_eq!(result.name, "factorial");
assert_eq!(result.addr, 0x2000100);
assert_eq!(result.offset, 0);
Expand All @@ -87,18 +84,22 @@ fn symbolize_elf_dwarf_gsym() {

// Now check that we can symbolize addresses at a positive offset from the
// start of the function.
for offset in 1..size {
let results = symbolizer
.symbolize(&src, &[0x2000100 + offset])
.unwrap()
.into_iter()
.collect::<Vec<_>>();
assert_eq!(results.len(), 1);

let (result, _addr_idx) = &results[0];
let offsets = (1..size).collect::<Vec<_>>();
let addrs = offsets
.iter()
.map(|offset| 0x2000100 + offset)
.collect::<Vec<_>>();
let results = symbolizer
.symbolize(&src, &addrs)
.unwrap()
.into_iter()
.collect::<Vec<_>>();
assert_eq!(results.len(), addrs.len());

for (i, (result, _addr_idx)) in results.into_iter().enumerate() {
assert_eq!(result.name, "factorial");
assert_eq!(result.addr, 0x2000100);
assert_eq!(result.offset, offset);
assert_eq!(result.offset, offsets[i]);

if has_src_loc {
let code_info = result.code_info.as_ref().unwrap();
Expand Down

0 comments on commit e672676

Please sign in to comment.