programs/uprobe: extract library path resolving

The function is extracted so that a test could be written. This test is
valid on linux-gnu targets, and it doesn't need any special privileges.
This is anticipation of removing the code that uses this functionality
(seemingly incidentally) from integration tests.
reviewable/pr638/r12
Andrew Werner 2 years ago
parent 8a48545694
commit 4dbe4b9dad

@ -82,36 +82,7 @@ impl UProbe {
target: T,
pid: Option<pid_t>,
) -> Result<UProbeLinkId, ProgramError> {
let target = target.as_ref();
let target_str = &*target.as_os_str().to_string_lossy();
let mut path = if let Some(pid) = pid {
find_lib_in_proc_maps(pid, target_str).map_err(|io_error| UProbeError::FileError {
filename: format!("/proc/{pid}/maps"),
io_error,
})?
} else {
None
};
if path.is_none() {
path = if target.is_absolute() {
Some(target_str)
} else {
let cache =
LD_SO_CACHE
.as_ref()
.map_err(|error| UProbeError::InvalidLdSoCache {
io_error: error.clone(),
})?;
cache.resolve(target_str)
}
.map(String::from)
};
let path = path.ok_or(UProbeError::InvalidTarget {
path: target.to_owned(),
})?;
let path = resolve_attach_path(target, pid)?;
let sym_offset = if let Some(fn_name) = fn_name {
resolve_symbol(&path, fn_name).map_err(|error| UProbeError::SymbolError {
@ -152,6 +123,60 @@ impl UProbe {
}
}
// Look up the path for the target. If it there is a pid, and the target is a library name
// that is in the process's memory map, use the path of that library. Otherwise, use the target as-is.
fn resolve_attach_path<T: AsRef<Path>>(
target: T,
pid: Option<pid_t>,
) -> Result<String, UProbeError> {
let target = target.as_ref();
let target_str = &*target.as_os_str().to_string_lossy();
let mut path = if let Some(pid) = pid {
find_lib_in_proc_maps(pid, target_str).map_err(|io_error| UProbeError::FileError {
filename: format!("/proc/{pid}/maps"),
io_error,
})?
} else {
None
};
if path.is_none() {
path = if target.is_absolute() {
Some(target_str)
} else {
let cache = LD_SO_CACHE
.as_ref()
.map_err(|error| UProbeError::InvalidLdSoCache {
io_error: error.clone(),
})?;
cache.resolve(target_str)
}
.map(String::from)
};
path.ok_or(UProbeError::InvalidTarget {
path: target.to_owned(),
})
}
// Only run this test on linux with glibc because only in that configuration do we know that we'll
// be dynamically linked to libc and can exercise resolving the path to libc via the current
// process's memory map.
#[cfg(all(target_os = "linux", target_env = "gnu"))]
#[test]
fn test_resolve_attach_path() {
// Look up the current process's pid.
let pid = std::process::id();
// Now let's resolve the path to libc. It should exist in the current process's memory map and
// then in the ld.so.cache.
let libc_path = resolve_attach_path("libc", Some(pid.try_into().unwrap())).unwrap();
// Make sure we got a path that contains libc.
assert!(libc_path.contains("libc"), "libc_path: {}", libc_path);
}
define_link_wrapper!(
/// The link used by [UProbe] programs.
UProbeLink,

Loading…
Cancel
Save