aya: refactor handling of /proc/$pid/maps

This commit refactors the handling of /proc/$pid/maps since the
collection previously assumed that all entries here could be
representeted in a HashMap. Those with a path component are stored
in a HashMap for fast lookup via library name. All other entries
are cached in a Vec to allow for filtering based on offsets, required
for supporting USDT probes.

Signed-off-by: Dave Tucker <dave@dtucker.co.uk>
reviewable/pr719/r3
Dave Tucker 3 years ago
parent bd5442a1de
commit 649074f7b5

@ -3,6 +3,7 @@ use libc::pid_t;
use object::{Object, ObjectSection, ObjectSymbol}; use object::{Object, ObjectSection, ObjectSymbol};
use std::{ use std::{
borrow::Cow, borrow::Cow,
collections::HashMap,
error::Error, error::Error,
ffi::CStr, ffi::CStr,
fs, fs,
@ -10,6 +11,7 @@ use std::{
mem, mem,
os::{fd::AsFd as _, raw::c_char}, os::{fd::AsFd as _, raw::c_char},
path::{Path, PathBuf}, path::{Path, PathBuf},
str::FromStr,
sync::Arc, sync::Arc,
}; };
use thiserror::Error; use thiserror::Error;
@ -136,12 +138,17 @@ fn resolve_attach_path<T: AsRef<Path>>(
}; };
let target_str = target.to_str().ok_or_else(invalid_target)?; let target_str = target.to_str().ok_or_else(invalid_target)?;
pid.and_then(|pid| { pid.and_then(|pid| {
find_lib_in_proc_maps(pid, target_str) ProcMap::new(pid)
.map_err(|io_error| UProbeError::FileError { .map_err(|source| UProbeError::ProcMapError { pid, source })
filename: format!("/proc/{pid}/maps"), .and_then(|proc_map_libs| {
io_error, proc_map_libs
.find_library_path_by_name(target_str)
.map_err(|io_error| UProbeError::FileError {
filename: format!("/proc/{pid}/maps"),
io_error,
})
.map(|v| v.map(Cow::Owned))
}) })
.map(|v| v.map(Cow::Owned))
.transpose() .transpose()
}) })
.or_else(|| target.is_absolute().then(|| Ok(Cow::Borrowed(target_str)))) .or_else(|| target.is_absolute().then(|| Ok(Cow::Borrowed(target_str))))
@ -247,43 +254,17 @@ pub enum UProbeError {
#[source] #[source]
io_error: io::Error, io_error: io::Error,
}, },
}
fn proc_maps_libs(pid: pid_t) -> Result<Vec<(String, String)>, io::Error> {
let maps_file = format!("/proc/{pid}/maps");
let data = fs::read_to_string(maps_file)?;
Ok(data
.lines()
.filter_map(|line| {
let line = line.split_whitespace().last()?;
if line.starts_with('/') {
let path = PathBuf::from(line);
let key = path.file_name().unwrap().to_string_lossy().into_owned();
Some((key, path.to_string_lossy().to_string()))
} else {
None
}
})
.collect())
}
fn find_lib_in_proc_maps(pid: pid_t, lib: &str) -> Result<Option<String>, io::Error> {
let libs = proc_maps_libs(pid)?;
let ret = if lib.contains(".so") {
libs.into_iter().find(|(k, _)| k.as_str().starts_with(lib))
} else {
libs.into_iter().find(|(k, _)| {
k.strip_prefix(lib)
.map(|k| k.starts_with(".so") || k.starts_with('-'))
.unwrap_or_default()
})
};
Ok(ret.map(|(_, v)| v)) /// There was en error resolving a path
#[error("error fetching libs for {pid}")]
ProcMapError {
/// The pid
pid: i32,
/// The [`ProcMapError`] that caused the error
#[source]
source: ProcMapError,
},
} }
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct CacheEntry { pub(crate) struct CacheEntry {
key: String, key: String,
@ -450,3 +431,228 @@ fn resolve_symbol(path: &str, symbol: &str) -> Result<u64, ResolveSymbolError> {
Ok(sym.address() - section.address() + offset) Ok(sym.address() - section.address() + offset)
} }
} }
/// Error reading from /proc/pid/maps
#[derive(Debug, Error)]
pub enum ProcMapError {
/// An [`io::Error`]
#[error(transparent)]
IoError(io::Error),
/// Error parsing a line of /proc/pid/maps
#[error("proc map entry parse error")]
ParseError,
}
/// The memory maps of a process.
///
/// This is read from /proc/`pid`/maps.
/// The information here may be used to resolve addresses to paths
pub struct ProcMap {
entries: Vec<ProcMapEntry>,
libraries: HashMap<String, String>,
}
impl ProcMap {
/// Create a new `ProcMap` from a given pid.
pub fn new(pid: pid_t) -> Result<Self, ProcMapError> {
let maps_file = format!("/proc/{}/maps", pid);
let data = fs::read_to_string(maps_file).map_err(ProcMapError::IoError)?;
let mut entries = vec![];
let mut libraries = HashMap::new();
for line in data.lines() {
let entry = ProcMapEntry::from_str(line)?;
if let Some(path) = &entry.path {
let p = PathBuf::from(path);
let filename = p.file_name().unwrap().to_string_lossy().into_owned();
let library_path = p.to_string_lossy().to_string();
libraries.entry(filename).or_insert(library_path);
}
entries.push(entry);
}
Ok(ProcMap { entries, libraries })
}
// Find the full path of a library by its name.
// This isn't part of the public API since it's really only useful for
// attaching uprobes.
fn find_library_path_by_name(&self, lib: &str) -> Result<Option<String>, io::Error> {
let ret = if lib.contains(".so") {
self.libraries
.iter()
.find(|(k, _)| k.as_str().starts_with(lib))
} else {
self.libraries.iter().find(|(k, _)| {
k.strip_prefix(lib)
.map(|k| k.starts_with(".so") || k.starts_with('-'))
.unwrap_or_default()
})
};
Ok(ret.map(|(_, v)| v.clone()))
}
/// Provides an iterator over all parsed memory map entries
/// for the process. This is useful to resolve
/// instruction pointers to a the shared object they belong to.
pub fn entries(&self) -> impl Iterator<Item = &ProcMapEntry> {
self.entries.iter()
}
}
/// A entry that has been parsed from /proc/`pid`/maps.
///
/// This contains information about a mapped portion of memory
/// for the process, ranging from address to address_end.
pub struct ProcMapEntry {
address: u64,
address_end: u64,
perms: String,
offset: u64,
dev: String,
inode: u32,
path: Option<String>,
}
impl ProcMapEntry {
/// The start address of the mapped memory
pub fn address(&self) -> u64 {
self.address
}
/// The end address of the mapped memory
pub fn address_end(&self) -> u64 {
self.address_end
}
/// The permissions of the mapped memory
pub fn perms(&self) -> &str {
&self.perms
}
/// The offset of the mapped memory
pub fn offset(&self) -> u64 {
self.offset
}
/// The device of the mapped memory
pub fn dev(&self) -> &str {
&self.dev
}
/// The inode of the mapped memory
pub fn inode(&self) -> u32 {
self.inode
}
/// The destination path of the mapped memory
pub fn path(&self) -> Option<&str> {
self.path.as_deref()
}
}
impl FromStr for ProcMapEntry {
type Err = ProcMapError;
fn from_str(line: &str) -> Result<Self, Self::Err> {
let mut parts = line.split_whitespace();
let mut next = || parts.next().ok_or(ProcMapError::ParseError);
let (address, address_end) = next()?
.split_once('-')
.and_then(|(a, b)| {
Some((
u64::from_str_radix(a, 16).ok()?,
u64::from_str_radix(b, 16).ok()?,
))
})
.ok_or(ProcMapError::ParseError)?;
let perms = next()?.to_string();
let offset = u64::from_str_radix(next()?, 16).map_err(|_| ProcMapError::ParseError)?;
let dev = next()?.to_string();
let inode = next()?.parse().map_err(|_| ProcMapError::ParseError)?;
let path = next().ok().and_then(|s| {
if s.starts_with('/') {
Some(s.to_string())
} else {
None
}
});
Ok(ProcMapEntry {
address,
address_end,
perms,
offset,
dev,
inode,
path,
})
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_parse_proc_map_entry_shared_lib() {
let s = "7ffd6fbea000-7ffd6fbec000 r-xp 00000000 00:00 0 [vdso]";
let proc_map = ProcMapEntry::from_str(s).unwrap();
assert_eq!(proc_map.address, 0x7ffd6fbea000);
assert_eq!(proc_map.address_end, 0x7ffd6fbec000);
assert_eq!(proc_map.perms, "r-xp");
assert_eq!(proc_map.offset, 0x0);
assert_eq!(proc_map.dev, "00:00");
assert_eq!(proc_map.inode, 0);
assert_eq!(proc_map.path, None);
}
#[test]
fn test_parse_proc_map_entry_absolute_path() {
let s = "7f1bca83a000-7f1bca83c000 rw-p 00036000 fd:01 2895508 /usr/lib64/ld-linux-x86-64.so.2";
let proc_map = ProcMapEntry::from_str(s).unwrap();
assert_eq!(proc_map.address, 0x7f1bca83a000);
assert_eq!(proc_map.address_end, 0x7f1bca83c000);
assert_eq!(proc_map.perms, "rw-p");
assert_eq!(proc_map.offset, 0x00036000);
assert_eq!(proc_map.dev, "fd:01");
assert_eq!(proc_map.inode, 2895508);
assert_eq!(
proc_map.path,
Some("/usr/lib64/ld-linux-x86-64.so.2".to_string())
);
}
#[test]
fn test_parse_proc_map_entry_all_zeros() {
let s = "7f1bca5f9000-7f1bca601000 rw-p 00000000 00:00 0";
let proc_map = ProcMapEntry::from_str(s).unwrap();
assert_eq!(proc_map.address, 0x7f1bca5f9000);
assert_eq!(proc_map.address_end, 0x7f1bca601000);
assert_eq!(proc_map.perms, "rw-p");
assert_eq!(proc_map.offset, 0x0);
assert_eq!(proc_map.dev, "00:00");
assert_eq!(proc_map.inode, 0);
assert_eq!(proc_map.path, None);
}
#[test]
fn test_proc_map_find_lib_by_name() {
let entry = ProcMapEntry::from_str(
"7fc4a9800000-7fc4a98ad000 r--p 00000000 00:24 18147308 /usr/lib64/libcrypto.so.3.0.9",
).unwrap();
let proc_map_libs = ProcMap {
entries: vec![entry],
libraries: HashMap::from([(
"libcrypto.so.3.0.9".to_owned(),
"/usr/lib64/libcrypto.so.3.0.9".to_owned(),
)]),
};
assert_eq!(
proc_map_libs
.find_library_path_by_name("libcrypto.so.3.0.9")
.unwrap(),
Some("/usr/lib64/libcrypto.so.3.0.9".to_owned())
);
}
}

@ -4319,6 +4319,40 @@ pub fn aya::programs::trace_point::TracePointLinkId::borrow_mut(&mut self) -> &m
impl<T> core::convert::From<T> for aya::programs::trace_point::TracePointLinkId impl<T> core::convert::From<T> for aya::programs::trace_point::TracePointLinkId
pub fn aya::programs::trace_point::TracePointLinkId::from(t: T) -> T pub fn aya::programs::trace_point::TracePointLinkId::from(t: T) -> T
pub mod aya::programs::uprobe pub mod aya::programs::uprobe
pub enum aya::programs::uprobe::ProcMapError
pub aya::programs::uprobe::ProcMapError::IoError(std::io::error::Error)
pub aya::programs::uprobe::ProcMapError::ParseError
impl core::error::Error for aya::programs::uprobe::ProcMapError
pub fn aya::programs::uprobe::ProcMapError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)>
impl core::fmt::Display for aya::programs::uprobe::ProcMapError
pub fn aya::programs::uprobe::ProcMapError::fmt(&self, __formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl core::fmt::Debug for aya::programs::uprobe::ProcMapError
pub fn aya::programs::uprobe::ProcMapError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl core::marker::Send for aya::programs::uprobe::ProcMapError
impl core::marker::Sync for aya::programs::uprobe::ProcMapError
impl core::marker::Unpin for aya::programs::uprobe::ProcMapError
impl !core::panic::unwind_safe::RefUnwindSafe for aya::programs::uprobe::ProcMapError
impl !core::panic::unwind_safe::UnwindSafe for aya::programs::uprobe::ProcMapError
impl<E> core::any::Provider for aya::programs::uprobe::ProcMapError where E: core::error::Error + core::marker::Sized
pub fn aya::programs::uprobe::ProcMapError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>)
impl<T, U> core::convert::Into<U> for aya::programs::uprobe::ProcMapError where U: core::convert::From<T>
pub fn aya::programs::uprobe::ProcMapError::into(self) -> U
impl<T, U> core::convert::TryFrom<U> for aya::programs::uprobe::ProcMapError where U: core::convert::Into<T>
pub type aya::programs::uprobe::ProcMapError::Error = core::convert::Infallible
pub fn aya::programs::uprobe::ProcMapError::try_from(value: U) -> core::result::Result<T, <T as core::convert::TryFrom<U>>::Error>
impl<T, U> core::convert::TryInto<U> for aya::programs::uprobe::ProcMapError where U: core::convert::TryFrom<T>
pub type aya::programs::uprobe::ProcMapError::Error = <U as core::convert::TryFrom<T>>::Error
pub fn aya::programs::uprobe::ProcMapError::try_into(self) -> core::result::Result<U, <U as core::convert::TryFrom<T>>::Error>
impl<T> alloc::string::ToString for aya::programs::uprobe::ProcMapError where T: core::fmt::Display + core::marker::Sized
pub fn aya::programs::uprobe::ProcMapError::to_string(&self) -> alloc::string::String
impl<T> core::any::Any for aya::programs::uprobe::ProcMapError where T: 'static + core::marker::Sized
pub fn aya::programs::uprobe::ProcMapError::type_id(&self) -> core::any::TypeId
impl<T> core::borrow::Borrow<T> for aya::programs::uprobe::ProcMapError where T: core::marker::Sized
pub fn aya::programs::uprobe::ProcMapError::borrow(&self) -> &T
impl<T> core::borrow::BorrowMut<T> for aya::programs::uprobe::ProcMapError where T: core::marker::Sized
pub fn aya::programs::uprobe::ProcMapError::borrow_mut(&mut self) -> &mut T
impl<T> core::convert::From<T> for aya::programs::uprobe::ProcMapError
pub fn aya::programs::uprobe::ProcMapError::from(t: T) -> T
pub enum aya::programs::uprobe::UProbeError pub enum aya::programs::uprobe::UProbeError
pub aya::programs::uprobe::UProbeError::FileError pub aya::programs::uprobe::UProbeError::FileError
pub aya::programs::uprobe::UProbeError::FileError::filename: alloc::string::String pub aya::programs::uprobe::UProbeError::FileError::filename: alloc::string::String
@ -4327,6 +4361,9 @@ pub aya::programs::uprobe::UProbeError::InvalidLdSoCache
pub aya::programs::uprobe::UProbeError::InvalidLdSoCache::io_error: alloc::sync::Arc<std::io::error::Error> pub aya::programs::uprobe::UProbeError::InvalidLdSoCache::io_error: alloc::sync::Arc<std::io::error::Error>
pub aya::programs::uprobe::UProbeError::InvalidTarget pub aya::programs::uprobe::UProbeError::InvalidTarget
pub aya::programs::uprobe::UProbeError::InvalidTarget::path: std::path::PathBuf pub aya::programs::uprobe::UProbeError::InvalidTarget::path: std::path::PathBuf
pub aya::programs::uprobe::UProbeError::ProcMapError
pub aya::programs::uprobe::UProbeError::ProcMapError::pid: i32
pub aya::programs::uprobe::UProbeError::ProcMapError::source: aya::programs::uprobe::ProcMapError
pub aya::programs::uprobe::UProbeError::SymbolError pub aya::programs::uprobe::UProbeError::SymbolError
pub aya::programs::uprobe::UProbeError::SymbolError::error: alloc::boxed::Box<(dyn core::error::Error + core::marker::Send + core::marker::Sync)> pub aya::programs::uprobe::UProbeError::SymbolError::error: alloc::boxed::Box<(dyn core::error::Error + core::marker::Send + core::marker::Sync)>
pub aya::programs::uprobe::UProbeError::SymbolError::symbol: alloc::string::String pub aya::programs::uprobe::UProbeError::SymbolError::symbol: alloc::string::String
@ -4363,6 +4400,64 @@ impl<T> core::borrow::BorrowMut<T> for aya::programs::uprobe::UProbeError where
pub fn aya::programs::uprobe::UProbeError::borrow_mut(&mut self) -> &mut T pub fn aya::programs::uprobe::UProbeError::borrow_mut(&mut self) -> &mut T
impl<T> core::convert::From<T> for aya::programs::uprobe::UProbeError impl<T> core::convert::From<T> for aya::programs::uprobe::UProbeError
pub fn aya::programs::uprobe::UProbeError::from(t: T) -> T pub fn aya::programs::uprobe::UProbeError::from(t: T) -> T
pub struct aya::programs::uprobe::ProcMap
impl aya::programs::uprobe::ProcMap
pub fn aya::programs::uprobe::ProcMap::entries(&self) -> impl core::iter::traits::iterator::Iterator<Item = &aya::programs::uprobe::ProcMapEntry>
pub fn aya::programs::uprobe::ProcMap::new(pid: libc::unix::pid_t) -> core::result::Result<Self, aya::programs::uprobe::ProcMapError>
impl core::marker::Send for aya::programs::uprobe::ProcMap
impl core::marker::Sync for aya::programs::uprobe::ProcMap
impl core::marker::Unpin for aya::programs::uprobe::ProcMap
impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::uprobe::ProcMap
impl core::panic::unwind_safe::UnwindSafe for aya::programs::uprobe::ProcMap
impl<T, U> core::convert::Into<U> for aya::programs::uprobe::ProcMap where U: core::convert::From<T>
pub fn aya::programs::uprobe::ProcMap::into(self) -> U
impl<T, U> core::convert::TryFrom<U> for aya::programs::uprobe::ProcMap where U: core::convert::Into<T>
pub type aya::programs::uprobe::ProcMap::Error = core::convert::Infallible
pub fn aya::programs::uprobe::ProcMap::try_from(value: U) -> core::result::Result<T, <T as core::convert::TryFrom<U>>::Error>
impl<T, U> core::convert::TryInto<U> for aya::programs::uprobe::ProcMap where U: core::convert::TryFrom<T>
pub type aya::programs::uprobe::ProcMap::Error = <U as core::convert::TryFrom<T>>::Error
pub fn aya::programs::uprobe::ProcMap::try_into(self) -> core::result::Result<U, <U as core::convert::TryFrom<T>>::Error>
impl<T> core::any::Any for aya::programs::uprobe::ProcMap where T: 'static + core::marker::Sized
pub fn aya::programs::uprobe::ProcMap::type_id(&self) -> core::any::TypeId
impl<T> core::borrow::Borrow<T> for aya::programs::uprobe::ProcMap where T: core::marker::Sized
pub fn aya::programs::uprobe::ProcMap::borrow(&self) -> &T
impl<T> core::borrow::BorrowMut<T> for aya::programs::uprobe::ProcMap where T: core::marker::Sized
pub fn aya::programs::uprobe::ProcMap::borrow_mut(&mut self) -> &mut T
impl<T> core::convert::From<T> for aya::programs::uprobe::ProcMap
pub fn aya::programs::uprobe::ProcMap::from(t: T) -> T
pub struct aya::programs::uprobe::ProcMapEntry
impl aya::programs::uprobe::ProcMapEntry
pub fn aya::programs::uprobe::ProcMapEntry::address(&self) -> u64
pub fn aya::programs::uprobe::ProcMapEntry::address_end(&self) -> u64
pub fn aya::programs::uprobe::ProcMapEntry::dev(&self) -> &str
pub fn aya::programs::uprobe::ProcMapEntry::inode(&self) -> u32
pub fn aya::programs::uprobe::ProcMapEntry::offset(&self) -> u64
pub fn aya::programs::uprobe::ProcMapEntry::path(&self) -> core::option::Option<&str>
pub fn aya::programs::uprobe::ProcMapEntry::perms(&self) -> &str
impl core::str::traits::FromStr for aya::programs::uprobe::ProcMapEntry
pub type aya::programs::uprobe::ProcMapEntry::Err = aya::programs::uprobe::ProcMapError
pub fn aya::programs::uprobe::ProcMapEntry::from_str(line: &str) -> core::result::Result<Self, Self::Err>
impl core::marker::Send for aya::programs::uprobe::ProcMapEntry
impl core::marker::Sync for aya::programs::uprobe::ProcMapEntry
impl core::marker::Unpin for aya::programs::uprobe::ProcMapEntry
impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::uprobe::ProcMapEntry
impl core::panic::unwind_safe::UnwindSafe for aya::programs::uprobe::ProcMapEntry
impl<T, U> core::convert::Into<U> for aya::programs::uprobe::ProcMapEntry where U: core::convert::From<T>
pub fn aya::programs::uprobe::ProcMapEntry::into(self) -> U
impl<T, U> core::convert::TryFrom<U> for aya::programs::uprobe::ProcMapEntry where U: core::convert::Into<T>
pub type aya::programs::uprobe::ProcMapEntry::Error = core::convert::Infallible
pub fn aya::programs::uprobe::ProcMapEntry::try_from(value: U) -> core::result::Result<T, <T as core::convert::TryFrom<U>>::Error>
impl<T, U> core::convert::TryInto<U> for aya::programs::uprobe::ProcMapEntry where U: core::convert::TryFrom<T>
pub type aya::programs::uprobe::ProcMapEntry::Error = <U as core::convert::TryFrom<T>>::Error
pub fn aya::programs::uprobe::ProcMapEntry::try_into(self) -> core::result::Result<U, <U as core::convert::TryFrom<T>>::Error>
impl<T> core::any::Any for aya::programs::uprobe::ProcMapEntry where T: 'static + core::marker::Sized
pub fn aya::programs::uprobe::ProcMapEntry::type_id(&self) -> core::any::TypeId
impl<T> core::borrow::Borrow<T> for aya::programs::uprobe::ProcMapEntry where T: core::marker::Sized
pub fn aya::programs::uprobe::ProcMapEntry::borrow(&self) -> &T
impl<T> core::borrow::BorrowMut<T> for aya::programs::uprobe::ProcMapEntry where T: core::marker::Sized
pub fn aya::programs::uprobe::ProcMapEntry::borrow_mut(&mut self) -> &mut T
impl<T> core::convert::From<T> for aya::programs::uprobe::ProcMapEntry
pub fn aya::programs::uprobe::ProcMapEntry::from(t: T) -> T
pub struct aya::programs::uprobe::UProbe pub struct aya::programs::uprobe::UProbe
impl aya::programs::uprobe::UProbe impl aya::programs::uprobe::UProbe
pub fn aya::programs::uprobe::UProbe::attach<T: core::convert::AsRef<std::path::Path>>(&mut self, fn_name: core::option::Option<&str>, offset: u64, target: T, pid: core::option::Option<libc::unix::pid_t>) -> core::result::Result<aya::programs::uprobe::UProbeLinkId, aya::programs::ProgramError> pub fn aya::programs::uprobe::UProbe::attach<T: core::convert::AsRef<std::path::Path>>(&mut self, fn_name: core::option::Option<&str>, offset: u64, target: T, pid: core::option::Option<libc::unix::pid_t>) -> core::result::Result<aya::programs::uprobe::UProbeLinkId, aya::programs::ProgramError>
@ -5454,6 +5549,9 @@ pub aya::programs::UProbeError::InvalidLdSoCache
pub aya::programs::UProbeError::InvalidLdSoCache::io_error: alloc::sync::Arc<std::io::error::Error> pub aya::programs::UProbeError::InvalidLdSoCache::io_error: alloc::sync::Arc<std::io::error::Error>
pub aya::programs::UProbeError::InvalidTarget pub aya::programs::UProbeError::InvalidTarget
pub aya::programs::UProbeError::InvalidTarget::path: std::path::PathBuf pub aya::programs::UProbeError::InvalidTarget::path: std::path::PathBuf
pub aya::programs::UProbeError::ProcMapError
pub aya::programs::UProbeError::ProcMapError::pid: i32
pub aya::programs::UProbeError::ProcMapError::source: aya::programs::uprobe::ProcMapError
pub aya::programs::UProbeError::SymbolError pub aya::programs::UProbeError::SymbolError
pub aya::programs::UProbeError::SymbolError::error: alloc::boxed::Box<(dyn core::error::Error + core::marker::Send + core::marker::Sync)> pub aya::programs::UProbeError::SymbolError::error: alloc::boxed::Box<(dyn core::error::Error + core::marker::Send + core::marker::Sync)>
pub aya::programs::UProbeError::SymbolError::symbol: alloc::string::String pub aya::programs::UProbeError::SymbolError::symbol: alloc::string::String

Loading…
Cancel
Save