rust-lang / rust-lang/backtrace-rs

Possible to export `Frame::resolve_symbol`?

Open
#690 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
628
Forks
291
PR merge metrics
No merged PRs in 30d

Description

Problem

  • I'm using eyre as my error handler and trying to write a custom error handler using eyre hook
  • Basically, a backtrace will be captured when error happens, and will be printed/logged later when handling the error.
  • The problem is that I want to capture the backtrace as unresolved and resolve it later in my custom handler so that passing the error around is cheaper. However, I'm not able to do this because, in order to use resolve, my captured backtrace must be a mutable reference. I also tried to get the backtrace frames and resolve each one manually, but I encountered the same issue: the backtrace frames are not &mut, and the Frame field of BacktraceFrame is not exported to use resolve_symbols method.

Proposed Solution

  • Can BacktraceFrame also have resolve_symbols which call frame.resolve_symbols and return all symbols that have been resolved? It already have symbols method but they are empty if the captured backtrace was unresolved

Example code

struct Hook {
    capture_backtrace: bool,
}

impl Hook {
    fn make_handler(&self, _error: &(dyn Error + 'static)) -> Handler {
        let backtrace = if self.capture_backtrace {
            Some(Backtrace::new_unresolved())
        } else {
            None
        };

        Handler { backtrace }
    }
}

struct Handler {
    // custom configured backtrace capture
    backtrace: Option<Backtrace>,
}

impl EyreHandler for Handler {
    fn debug(&self, error: &(dyn Error + 'static), f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if f.alternate() {
            return fmt::Debug::fmt(error, f);
        }

        let errors = iter::successors(Some(error), |error| (*error).source());

        for (ind, error) in errors.enumerate() {
            write!(f, "\n{:>4}: {}", ind, error)?;
        }

        if let Some(backtrace) = self.backtrace.as_ref() {
            writeln!(f, "\n\nBacktrace:\n{:?}", backtrace)?;
            let frames = backtrace.frames();

            for (ind, frame) in frames.iter().enumerate() {
                writeln!(f, "\n{:>4}: {:?}", ind, frame.resolve())?; // cannot resolve because frame is not &mut

                // My workaround
                // let ip = frame.ip();
                // backtrace::resolve(ip, |symbol| {
                //     println!("{:?}", symbol);
                // });

                // Proposed solution
                // let backtrace_symbols = frame.resolve_symbols();
                // println!("{:?}", backtrace_symbols);
            }
        }

        Ok(())
    }
}

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading the existing Frame::resolve_symbols and BacktraceFrame::symbols APIs, along with the BacktraceFrame and Frame types described in the issue. Check how unresolved frames are represented and how mutable access is handled; done means exposing a BacktraceFrame-level resolution method that returns the resolved symbols without requiring callers to access the private Frame field.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
devtools
Issue type
Feature
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.