Skip to content

Commit

Permalink
capi: Make debug directories to search configurable
Browse files Browse the repository at this point in the history
Make the list of debug directories configurable, similar to what commit
e62caa9 ("Make debug directories to search configurable") did for
the Rust crate.

Signed-off-by: Daniel Müller <deso@posteo.net>
  • Loading branch information
d-e-s-o committed Jun 3, 2024
1 parent baf25d4 commit 49b67f5
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 5 deletions.
1 change: 1 addition & 0 deletions capi/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
Unreleased
----------
- Added `debug_dirs` attribute to `blaze_symbolizer_opts`
- Added `cache_maps` attribute to `blaze_normalizer_opts`
- Introduced `blaze_err` enum and adjusted all fallible functions to
set a thread local error
Expand Down
1 change: 1 addition & 0 deletions capi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,5 @@ blazesym-c = {path = ".", features = ["check-doc-snippets"]}
# TODO: Use 0.5.2 once released.
criterion = {git = "https://github.com/bheisler/criterion.rs.git", rev = "b913e232edd98780961ecfbae836ec77ede49259", default-features = false, features = ["rayon", "cargo_bench_support"]}
libc = "0.2.137"
tempfile = "3.4"
test-log = {version = "0.2.14", default-features = false, features = ["trace"]}
17 changes: 17 additions & 0 deletions capi/include/blazesym.h
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,23 @@ typedef struct blaze_symbolizer_opts {
* ensure compatibility in the presence of member additions.
*/
size_t type_size;
/**
* Array of debug directories to search for split debug information.
*
* These directories will be consulted (in given order) when resolving
* debug links in binaries. By default and when this member is NULL,
* `/usr/lib/debug` and `/lib/debug/` will be searched. Setting an array
* here will overwrite these defaults, so make sure to include these
* directories as desired.
*
* Note that the directory containing a symbolization source is always an
* implicit candidate target directory of the highest precedence.
*/
const char *const *debug_dirs;
/**
* The number of array elements in `debug_dirs`.
*/
size_t debug_dirs_len;
/**
* Whether or not to automatically reload file system based
* symbolization sources that were updated since the last
Expand Down
147 changes: 142 additions & 5 deletions capi/src/symbolize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,19 @@ pub struct blaze_symbolizer_opts {
/// Make sure to initialize it to `sizeof(<type>)`. This member is used to
/// ensure compatibility in the presence of member additions.
pub type_size: usize,
/// Array of debug directories to search for split debug information.
///
/// These directories will be consulted (in given order) when resolving
/// debug links in binaries. By default and when this member is NULL,
/// `/usr/lib/debug` and `/lib/debug/` will be searched. Setting an array
/// here will overwrite these defaults, so make sure to include these
/// directories as desired.
///
/// Note that the directory containing a symbolization source is always an
/// implicit candidate target directory of the highest precedence.
pub debug_dirs: *const *const c_char,
/// The number of array elements in `debug_dirs`.
pub debug_dirs_len: usize,
/// Whether or not to automatically reload file system based
/// symbolization sources that were updated since the last
/// symbolization operation.
Expand All @@ -450,6 +463,8 @@ impl Default for blaze_symbolizer_opts {
fn default() -> Self {
Self {
type_size: mem::size_of::<Self>(),
debug_dirs: ptr::null(),
debug_dirs_len: 0,
auto_reload: false,
code_info: false,
inlined_fns: false,
Expand Down Expand Up @@ -504,19 +519,39 @@ pub unsafe extern "C" fn blaze_symbolizer_new_opts(

let blaze_symbolizer_opts {
type_size: _,
debug_dirs,
debug_dirs_len,
auto_reload,
code_info,
inlined_fns,
demangle,
reserved: _,
} = opts;

let symbolizer = Symbolizer::builder()
let builder = Symbolizer::builder()
.enable_auto_reload(auto_reload)
.enable_code_info(code_info)
.enable_inlined_fns(inlined_fns)
.enable_demangling(demangle)
.build();
.enable_demangling(demangle);

let builder = if debug_dirs.is_null() {
builder
} else {
// SAFETY: The caller ensures that the pointer is valid and the count
// matches.
let slice = unsafe { slice_from_user_array(debug_dirs, debug_dirs_len) };
let iter = slice.iter().map(|cstr| {
Path::new(OsStr::from_bytes(
// SAFETY: The caller ensures that valid C strings are
// provided.
unsafe { CStr::from_ptr(cstr.cast()) }.to_bytes(),
))
});

builder.set_debug_dirs(Some(iter))
};

let symbolizer = builder.build();
let symbolizer_box = Box::new(symbolizer);
let () = set_last_err(blaze_err::BLAZE_ERR_OK);
Box::into_raw(symbolizer_box)
Expand Down Expand Up @@ -955,6 +990,7 @@ mod tests {
use super::*;

use std::ffi::CString;
use std::fs::copy;
use std::fs::read as read_file;
use std::hint::black_box;
use std::io::Error;
Expand All @@ -966,6 +1002,8 @@ mod tests {
use blazesym::symbolize::Reason;
use blazesym::Pid;

use tempfile::tempdir;

use crate::blaze_err_last;


Expand All @@ -978,7 +1016,7 @@ mod tests {
assert_eq!(mem::size_of::<blaze_symbolize_src_process>(), 16);
assert_eq!(mem::size_of::<blaze_symbolize_src_gsym_data>(), 24);
assert_eq!(mem::size_of::<blaze_symbolize_src_gsym_file>(), 16);
assert_eq!(mem::size_of::<blaze_symbolizer_opts>(), 16);
assert_eq!(mem::size_of::<blaze_symbolizer_opts>(), 32);
assert_eq!(mem::size_of::<blaze_symbolize_code_info>(), 32);
assert_eq!(mem::size_of::<blaze_symbolize_inlined_fn>(), 48);
assert_eq!(mem::size_of::<blaze_sym>(), 80);
Expand Down Expand Up @@ -1084,7 +1122,7 @@ mod tests {
};
assert_eq!(
format!("{opts:?}"),
"blaze_symbolizer_opts { type_size: 16, auto_reload: false, code_info: false, inlined_fns: false, demangle: true, reserved: [0, 0, 0, 0] }"
"blaze_symbolizer_opts { type_size: 16, debug_dirs: 0x0, debug_dirs_len: 0, auto_reload: false, code_info: false, inlined_fns: false, demangle: true, reserved: [0, 0, 0, 0] }"
);
}

Expand Down Expand Up @@ -1603,4 +1641,103 @@ mod tests {
let () = unsafe { blaze_result_free(result) };
let () = unsafe { blaze_symbolizer_free(symbolizer) };
}

/// Check that we can handle no configured debug directories.
#[test]
fn symbolize_no_debug_dirs() {
let dir = tempdir().unwrap();
let path = Path::new(&env!("CARGO_MANIFEST_DIR"))
.join("..")
.join("data")
.join("test-stable-addrs-stripped-with-link.bin");
let dst = dir.path().join("test-stable-addrs-stripped-with-link.bin");
let _count = copy(path, &dst).unwrap();

let debug_dirs = [];
let opts = blaze_symbolizer_opts {
debug_dirs: debug_dirs.as_ptr(),
debug_dirs_len: debug_dirs.len(),
code_info: true,
inlined_fns: true,
demangle: true,
..Default::default()
};
let symbolizer = unsafe { blaze_symbolizer_new_opts(&opts) };

let path_c = CString::new(dst.to_str().unwrap()).unwrap();
let elf_src = blaze_symbolize_src_elf {
path: path_c.as_ptr(),
debug_syms: true,
..Default::default()
};
let addrs = [0x2000100];
let result = unsafe {
blaze_symbolize_elf_virt_offsets(symbolizer, &elf_src, addrs.as_ptr(), addrs.len())
};
assert!(!result.is_null());

let result = unsafe { &*result };
assert_eq!(result.cnt, 1);
let syms = unsafe { slice::from_raw_parts(result.syms.as_ptr(), result.cnt) };
let sym = &syms[0];
// Shouldn't have symbolized because the debug link target cannot be
// found.
assert_eq!(sym.name, ptr::null());

let () = unsafe { blaze_result_free(result) };
let () = unsafe { blaze_symbolizer_free(symbolizer) };
}

/// Make sure that debug directories are configurable.
#[test]
fn symbolize_configurable_debug_dirs() {
let debug_dir1 = tempdir().unwrap();
let debug_dir1_c = CString::new(debug_dir1.path().to_str().unwrap()).unwrap();
let debug_dir2 = tempdir().unwrap();
let debug_dir2_c = CString::new(debug_dir2.path().to_str().unwrap()).unwrap();

let src = Path::new(&env!("CARGO_MANIFEST_DIR"))
.join("..")
.join("data")
.join("test-stable-addrs-dwarf-only.dbg");
let dst = debug_dir2.path().join("test-stable-addrs-dwarf-only.dbg");
let _count = copy(src, dst).unwrap();

let debug_dirs = [debug_dir1_c.as_ptr(), debug_dir2_c.as_ptr()];
let opts = blaze_symbolizer_opts {
debug_dirs: debug_dirs.as_ptr(),
debug_dirs_len: debug_dirs.len(),
code_info: true,
inlined_fns: true,
demangle: true,
..Default::default()
};
let symbolizer = unsafe { blaze_symbolizer_new_opts(&opts) };

let path = Path::new(&env!("CARGO_MANIFEST_DIR"))
.join("..")
.join("data")
.join("test-stable-addrs-stripped-with-link.bin");
let path_c = CString::new(path.to_str().unwrap()).unwrap();
let elf_src = blaze_symbolize_src_elf {
path: path_c.as_ptr(),
debug_syms: true,
..Default::default()
};
let addrs = [0x2000100];
let result = unsafe {
blaze_symbolize_elf_virt_offsets(symbolizer, &elf_src, addrs.as_ptr(), addrs.len())
};
assert!(!result.is_null());

let result = unsafe { &*result };
assert_eq!(result.cnt, 1);
let syms = unsafe { slice::from_raw_parts(result.syms.as_ptr(), result.cnt) };
let sym = &syms[0];
let name = unsafe { CStr::from_ptr(sym.name) };
assert_eq!(name.to_str().unwrap(), "factorial");

let () = unsafe { blaze_result_free(result) };
let () = unsafe { blaze_symbolizer_free(symbolizer) };
}
}

0 comments on commit 49b67f5

Please sign in to comment.