|
|
|
@ -1,12 +1,7 @@
|
|
|
|
|
//! A hash map of kernel or user space stack traces.
|
|
|
|
|
//!
|
|
|
|
|
//! See [`StackTraceMap`] for documentation and examples.
|
|
|
|
|
use std::{
|
|
|
|
|
borrow::{Borrow, Cow},
|
|
|
|
|
fs, io, mem,
|
|
|
|
|
path::Path,
|
|
|
|
|
str::FromStr,
|
|
|
|
|
};
|
|
|
|
|
use std::{borrow::Borrow, fs, io, mem, path::Path, str::FromStr};
|
|
|
|
|
|
|
|
|
|
use crate::{
|
|
|
|
|
maps::{IterableMap, MapData, MapError, MapIter, MapKeys},
|
|
|
|
@ -51,15 +46,19 @@ use crate::{
|
|
|
|
|
/// // here we resolve symbol names using kernel symbols. If this was a user space stack (for
|
|
|
|
|
/// // example captured from a uprobe), you'd have to load the symbols using some other mechanism
|
|
|
|
|
/// // (eg loading the target binary debuginfo)
|
|
|
|
|
/// for frame in stack_trace.resolve(&ksyms).frames() {
|
|
|
|
|
/// println!(
|
|
|
|
|
/// "{:#x} {}",
|
|
|
|
|
/// frame.ip,
|
|
|
|
|
/// frame
|
|
|
|
|
/// .symbol_name
|
|
|
|
|
/// .as_deref()
|
|
|
|
|
/// .unwrap_or("[unknown symbol name]")
|
|
|
|
|
/// );
|
|
|
|
|
/// for frame in stack_trace.frames() {
|
|
|
|
|
/// if let Some(sym) = ksyms.range(..=frame.ip).next_back().map(|(_, s)| s) {
|
|
|
|
|
/// println!(
|
|
|
|
|
/// "{:#x} {}",
|
|
|
|
|
/// frame.ip,
|
|
|
|
|
/// sym
|
|
|
|
|
/// );
|
|
|
|
|
/// } else {
|
|
|
|
|
/// println!(
|
|
|
|
|
/// "{:#x}",
|
|
|
|
|
/// frame.ip
|
|
|
|
|
/// );
|
|
|
|
|
/// }
|
|
|
|
|
/// }
|
|
|
|
|
///
|
|
|
|
|
/// # Ok::<(), Error>(())
|
|
|
|
@ -118,10 +117,7 @@ impl<T: Borrow<MapData>> StackTraceMap<T> {
|
|
|
|
|
let frames = frames
|
|
|
|
|
.into_iter()
|
|
|
|
|
.take_while(|ip| *ip != 0)
|
|
|
|
|
.map(|ip| StackFrame {
|
|
|
|
|
ip,
|
|
|
|
|
symbol_name: None,
|
|
|
|
|
})
|
|
|
|
|
.map(|ip| StackFrame { ip })
|
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
|
|
|
|
Ok(StackTrace {
|
|
|
|
@ -162,12 +158,6 @@ impl<'a, T: Borrow<MapData>> IntoIterator for &'a StackTraceMap<T> {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// A resolver for symbols based on an address obtained from a stack trace.
|
|
|
|
|
pub trait SymbolResolver {
|
|
|
|
|
/// Resolve a symbol for a given address, if possible.
|
|
|
|
|
fn resolve_symbol(&self, addr: u64) -> Option<Cow<'_, str>>;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// A kernel or user space stack trace.
|
|
|
|
|
///
|
|
|
|
|
/// See the [`StackTraceMap`] documentation for examples.
|
|
|
|
@ -178,19 +168,6 @@ pub struct StackTrace {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl StackTrace {
|
|
|
|
|
/// Resolves symbol names using the given symbol map.
|
|
|
|
|
///
|
|
|
|
|
/// You can use [`util::kernel_symbols()`](crate::util::kernel_symbols) to load kernel symbols. For
|
|
|
|
|
/// user-space traces you need to provide the symbols, for example loading
|
|
|
|
|
/// them from debug info.
|
|
|
|
|
pub fn resolve<R: SymbolResolver>(&mut self, symbols: &R) -> &StackTrace {
|
|
|
|
|
for frame in self.frames.iter_mut() {
|
|
|
|
|
frame.symbol_name = symbols.resolve_symbol(frame.ip).map(|s| s.into_owned())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Returns the frames in this stack trace.
|
|
|
|
|
pub fn frames(&self) -> &[StackFrame] {
|
|
|
|
|
&self.frames
|
|
|
|
@ -201,11 +178,6 @@ impl StackTrace {
|
|
|
|
|
pub struct StackFrame {
|
|
|
|
|
/// The instruction pointer of this frame.
|
|
|
|
|
pub ip: u64,
|
|
|
|
|
/// The symbol name corresponding to the start of this frame.
|
|
|
|
|
///
|
|
|
|
|
/// Set to `Some()` if the frame address can be found in the symbols passed
|
|
|
|
|
/// to [`StackTrace::resolve`].
|
|
|
|
|
pub symbol_name: Option<String>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn sysctl<T: FromStr>(key: &str) -> Result<T, io::Error> {
|
|
|
|
|