Merge pull request #718 from ajwerner/better-code

uprobe: refactor target resolution
reviewable/pr709/r3
ajwerner 1 year ago committed by GitHub
commit ef6308b640
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -2,6 +2,7 @@
use libc::pid_t; use libc::pid_t;
use object::{Object, ObjectSection, ObjectSymbol}; use object::{Object, ObjectSection, ObjectSymbol};
use std::{ use std::{
borrow::Cow,
error::Error, error::Error,
ffi::CStr, ffi::CStr,
fs, fs,
@ -82,7 +83,7 @@ impl UProbe {
target: T, target: T,
pid: Option<pid_t>, pid: Option<pid_t>,
) -> Result<UProbeLinkId, ProgramError> { ) -> Result<UProbeLinkId, ProgramError> {
let path = resolve_attach_path(target, pid)?; let path = resolve_attach_path(&target, pid)?;
let sym_offset = if let Some(fn_name) = fn_name { let sym_offset = if let Some(fn_name) = fn_name {
resolve_symbol(&path, fn_name).map_err(|error| UProbeError::SymbolError { resolve_symbol(&path, fn_name).map_err(|error| UProbeError::SymbolError {
@ -124,41 +125,36 @@ impl UProbe {
} }
fn resolve_attach_path<T: AsRef<Path>>( fn resolve_attach_path<T: AsRef<Path>>(
target: T, target: &T,
pid: Option<pid_t>, pid: Option<pid_t>,
) -> Result<String, UProbeError> { ) -> Result<Cow<'_, str>, UProbeError> {
// Look up the path for the target. If it there is a pid, and the target is a library name that // Look up the path for the target. If it there is a pid, and the target is a library name
// is in the process's memory map, use the path of that library. Otherwise, use the target // that is in the process's memory map, use the path of that library. Otherwise, use the target as-is.
// as-is.
let target = target.as_ref(); let target = target.as_ref();
let target_str = &*target.as_os_str().to_string_lossy(); let invalid_target = || UProbeError::InvalidTarget {
path: target.to_owned(),
let mut path = if let Some(pid) = pid { };
find_lib_in_proc_maps(pid, target_str).map_err(|io_error| UProbeError::FileError { let target_str = target.to_str().ok_or_else(invalid_target)?;
pid.and_then(|pid| {
find_lib_in_proc_maps(pid, target_str)
.map_err(|io_error| UProbeError::FileError {
filename: format!("/proc/{pid}/maps"), filename: format!("/proc/{pid}/maps"),
io_error, io_error,
})? })
} else { .map(|v| v.map(Cow::Owned))
None .transpose()
}; })
.or_else(|| target.is_absolute().then(|| Ok(Cow::Borrowed(target_str))))
if path.is_none() { .or_else(|| {
path = if target.is_absolute() { LD_SO_CACHE
Some(target_str)
} else {
let cache = LD_SO_CACHE
.as_ref() .as_ref()
.map_err(|error| UProbeError::InvalidLdSoCache { .map_err(|error| UProbeError::InvalidLdSoCache {
io_error: error.clone(), io_error: error.clone(),
})?;
cache.resolve(target_str)
}
.map(String::from)
};
path.ok_or(UProbeError::InvalidTarget {
path: target.to_owned(),
}) })
.map(|cache| cache.resolve(target_str).map(Cow::Borrowed))
.transpose()
})
.unwrap_or_else(|| Err(invalid_target()))
} }
// Only run this test on linux with glibc because only in that configuration do we know that we'll // Only run this test on linux with glibc because only in that configuration do we know that we'll
@ -175,7 +171,7 @@ fn test_resolve_attach_path() {
// Now let's resolve the path to libc. It should exist in the current process's memory map and // 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. // then in the ld.so.cache.
let libc_path = resolve_attach_path("libc", Some(pid)).unwrap(); let libc_path = resolve_attach_path(&"libc", Some(pid)).unwrap();
// Make sure we got a path that contains libc. // Make sure we got a path that contains libc.
assert!(libc_path.contains("libc"), "libc_path: {}", libc_path); assert!(libc_path.contains("libc"), "libc_path: {}", libc_path);
@ -276,16 +272,16 @@ fn find_lib_in_proc_maps(pid: pid_t, lib: &str) -> Result<Option<String>, io::Er
let libs = proc_maps_libs(pid)?; let libs = proc_maps_libs(pid)?;
let ret = if lib.contains(".so") { let ret = if lib.contains(".so") {
libs.iter().find(|(k, _)| k.as_str().starts_with(lib)) libs.into_iter().find(|(k, _)| k.as_str().starts_with(lib))
} else { } else {
let lib = lib.to_string(); libs.into_iter().find(|(k, _)| {
let lib1 = lib.clone() + ".so"; k.strip_prefix(lib)
let lib2 = lib + "-"; .map(|k| k.starts_with(".so") || k.starts_with('-'))
libs.iter() .unwrap_or_default()
.find(|(k, _)| k.starts_with(&lib1) || k.starts_with(&lib2)) })
}; };
Ok(ret.map(|(_, v)| v.clone())) Ok(ret.map(|(_, v)| v))
} }
#[derive(Debug)] #[derive(Debug)]

Loading…
Cancel
Save