1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
//! Stack trace (backtrace) functionality using DWARF debugging information.
//!
//! There are two main ways of obtaining stack traces:
//! 1. Using the frame pointer register to find the previous stack frame.
//! 2. Using DWARF debugging information to understand the layout of each stack frame.
//!
//! We support both ways, but prefer #2 because it doesn't suffer from the
//! compatibility and performance drawbacks of #1.
//! See the `stack_trace_frame_pointers` crate for the #1 functionality.
//!
//! This crate offers support for #2.
//! The advantage of using this is that it should always be possible
//! regardless of how the compiler was configured.
//! However, this crate requires more dependencies, and if object files have been
//! specifically stripped of DWARF info, then we won't be able to recurse up the call stack.
//!
#![no_std]
extern crate alloc;
#[macro_use] extern crate log;
extern crate mod_mgmt;
extern crate task;
extern crate unwind;
extern crate fallible_iterator;
pub use mod_mgmt::{CrateNamespace, StrongSectionRef};
pub use task::get_my_current_task;
use unwind::{StackFrame, StackFrameIter};
use fallible_iterator::FallibleIterator;
/// Get a stack trace using the default stack tracer based on DWARF debug info.
///
/// # Arguments
/// * `on_each_stack_frame`: (a mutable reference to) the function that will be called
/// for each stack frame in the call stack.
///
/// The function is called with two arguments:
/// 1. a `StackFrame` instance that contains information about that frame,
/// 2. a reference to the current `StackFrameIter`, which can be used to obtain
/// register values that existed at this frame in the call stack.
///
/// The function should return `true` if it wants to continue iterating up the call stack,
/// or `false` if it wants the iteration to stop.
/// * `max_recursion`: an optional maximum number of stack frames to recurse up the call stack.
///
/// # Examples
/// Typical usage would involve using the stack frame's call site address to print out
/// a standard backtrace of the call stack, as such:
/// ```
/// stack_trace(
/// &mut |stack_frame, _stack_frame_iter| {
/// println!("{:>#018X}", stack_frame.call_site_address());
/// true // keep iterating
/// },
/// None,
/// );
/// ```
#[inline(never)]
pub fn stack_trace(
on_each_stack_frame: &mut dyn FnMut(StackFrame, &StackFrameIter) -> bool,
max_recursion: Option<usize>,
) -> Result<(), &'static str> {
let max_recursion = max_recursion.unwrap_or(usize::MAX);
unwind::invoke_with_current_registers(&mut |registers| {
let namespace = task::with_current_task(|t| t.get_namespace().clone())
.or_else(|_| mod_mgmt::get_initial_kernel_namespace().cloned().ok_or(()))
.map_err(|_| "couldn't get current task's namespace or default namespace")?;
let mut stack_frame_iter = StackFrameIter::new(namespace, registers);
// iterate over each frame in the call stack
let mut i = 0;
while let Some(frame) = stack_frame_iter.next()? {
let keep_going = on_each_stack_frame(frame, &stack_frame_iter);
if !keep_going {
return Ok(());
}
i += 1;
if i == max_recursion {
trace!("stack_trace(): reached maximum recursion depth of {} stack frames", max_recursion);
return Err("reached recursion limit for stack frames");
}
}
Ok(())
})
}