Type Definition gimli::UnwindResult[][src]

type UnwindResult<T, UnwindContext> = Result<T, (Error, UnwindContext)>;

Either a value of Ok(T), or a pair of an error and uninitialized unwind context of Err((gimli::Error, UnwindContext)).

Creating an unwinding context is not signal safe, because it involves allocation which in turn involves locking. Using an existing unwinding context is signal safe, however. Therefore, it is critical that we can recover and reuse unwinding contexts even in the face of errors, because we might not even be able to create a new context otherwise. A secondary benefit is that this should be more performant than recreating contexts anyways.

For example, you might want to perform many different operations that involve evaluating unwinding information, and reuse the same context for all of them:

/// My type that does many unwinding things for me, reusing a single unwinding
/// context for all of them.
pub struct MyUnwinder<S, R>
where
    S: gimli::UnwindSection<R>,
    R: gimli::Reader
{
    ctx: Option<gimli::UninitializedUnwindContext<S, R>>,
}

impl<S, R> MyUnwinder<S, R>
where
    S: gimli::UnwindSection<R>,
    R: gimli::Reader
{
    /// Call `f` on each row in the given FDE's unwind table.
    fn each_unwind_row<F>(
        &mut self,
        fde: &gimli::FrameDescriptionEntry<S, R, R::Offset>,
        mut f: F,
    ) -> gimli::Result<()>
    where
        F: FnMut(&gimli::UnwindTableRow<R>),
    {
        // Take the `UninitializedUnwindContext` out of `self` so we can turn it into
        // an `InitializedUnwindContext`. We must replace it again before returning.
        let ctx = self.ctx.take().expect("Invariant: always Some at start of function");

        // Initialize the context with this FDE's CIE. This returns an `UnwindResult`,
        // which hands us the context back in case of failure.
        let mut ctx = match ctx.initialize(fde.cie()) {
            Ok(ctx) => ctx,
            Err((e, ctx)) => {
                // There was an error! Before propagating the error, recover this `ctx`
                // so we can reuse it.
                self.ctx = Some(ctx);
                return Err(e);
            }
        };

        // Rather than using `?` to immediately propagate any errors returned
        // from `next_row`, we'll need to recover the context before returning.
        // Unfortunately, this also involves funky scopes to satisfy the borrow
        // checker, because `ctx` is borrowed by `table`.
        let result = {
            let mut table = gimli::UnwindTable::new(&mut ctx, fde);

            loop {
                match table.next_row() {
                    // Another row, so call `f`.
                    Ok(Some(row)) => f(row),
                    // We're all done iterating rows in this FDE.
                    Ok(None) => break Ok(()),
                    // Propagate the error up.
                    Err(e) => break Err(e),
                }
            }
        };

        // Reset the initialized context back to an uninitialized context and
        // move it back into `self`, so it can be used to unwind with more FDEs
        // in the future.
        self.ctx = Some(ctx.reset());

        result
    }
}