简体   繁体   中英

How does __rust_begin_short_backtrace work in Rust?

As titled.

I know that __rust_begin_short_backtrace is used for stack backtracing, but how does it work actually? I find the implementation of it is really short just like below. And what it does is only calling the passed-in function indirectly, and return back the result. I also find the counterpart function __rust_end_short_backtrace which has totally identical implementation. The code is at library/std/src/sys_common/backtrace.rs .

/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that
/// this is only inline(never) when backtraces in libstd are enabled, otherwise
/// it's fine to optimize away.
#[cfg_attr(feature = "backtrace", inline(never))]
pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T
where
    F: FnOnce() -> T,
{
    let result = f();

    // prevent this frame from being tail-call optimised away
    crate::hint::black_box(());

    result
}

Another part of the related implementation is also at " library/std/src/sys_common/backtrace.rs ". Below is a snippet of code of this part which I think is highly related and important, but I don't understand the logic here that how Rust deals with the symbols that relate to the previous two functions:

 backtrace_rs::trace_unsynchronized(|frame| {
    if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES {
        return false;
    }

    let mut hit = false;
    let mut stop = false;
    backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| {
        hit = true;
        if print_fmt == PrintFmt::Short {
            if let Some(sym) = symbol.name().and_then(|s| s.as_str()) {
                if sym.contains("__rust_begin_short_backtrace") {
                    stop = true;
                    return;
                }
                if sym.contains("__rust_end_short_backtrace") {
                    start = true;
                    return;
                }
            }
        }

        if start {
            res = bt_fmt.frame().symbol(frame, symbol);
        }
    });
    if stop {
        return false;
    }
    if !hit {
        if start {
            res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
        }
    }

    idx += 1;
    res.is_ok()
});

Rust is inserting these "dummy symbols" to allow a short backtrace.

Consider this code

fn a() {
    b()
}

fn b() {
    c()
}

fn c() {
    d()
}

fn d() {
    panic!()
}

fn main() {
    a()
}

This gives a nice backtrace

$ rustc demo.rs
$ RUST_BACKTRACE=1 ./demo
thread 'main' panicked at 'explicit panic', demo.rs:14:5
stack backtrace:
   0: std::panicking::begin_panic
   1: demo::d
   2: demo::c
   3: demo::b
   4: demo::a
   5: demo::main
   6: core::ops::function::FnOnce::call_once
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

If we instead use RUST_BACKTRACE=full

$ RUST_BACKTRACE=full ./demo
thread 'main' panicked at 'explicit panic', demo.rs:14:5
stack backtrace:
   0:        0x107e34fe4 - std::backtrace_rs::backtrace::libunwind::trace::ha70d3c0580051b5e
                               at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/std/src/../../backtrace/src/backtrace/libunwind.rs:90:5
   1:        0x107e34fe4 - std::backtrace_rs::backtrace::trace_unsynchronized::h70c3b3ef22cddd13
                               at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
   2:        0x107e34fe4 - std::sys_common::backtrace::_print_fmt::h698e42c1766250fa
                               at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/std/src/sys_common/backtrace.rs:67:5
   3:        0x107e34fe4 - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h18cc31b07c2f1a67
                               at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/std/src/sys_common/backtrace.rs:46:22
   4:        0x107e4808d - core::fmt::write::h24f8349e8e89c9af
                               at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/core/src/fmt/mod.rs:1096:17
   5:        0x107e33046 - std::io::Write::write_fmt::hc54d7d6e95b15753
                               at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/std/src/io/mod.rs:1568:15
   6:        0x107e36b79 - std::sys_common::backtrace::_print::h07ca439149358748
                               at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/std/src/sys_common/backtrace.rs:49:5
   7:        0x107e36b79 - std::sys_common::backtrace::print::hb7331bf9c4b208ca
                               at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/std/src/sys_common/backtrace.rs:36:9
   8:        0x107e36b79 - std::panicking::default_hook::{{closure}}::h11b550d560f5cc66
                               at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/std/src/panicking.rs:208:50
   9:        0x107e36709 - std::panicking::default_hook::he168e99d1cf91c3c
                               at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/std/src/panicking.rs:225:9
  10:        0x107e371fb - std::panicking::rust_panic_with_hook::hf87bfc4afef21ea6
                               at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/std/src/panicking.rs:591:17
  11:        0x107e18d27 - std::panicking::begin_panic::{{closure}}::h631923d2be23e79e
  12:        0x107e18998 - std::sys_common::backtrace::__rust_end_short_backtrace::h891b6a0b6f9c1b80
  13:        0x107e4bcfb - std::panicking::begin_panic::hd2dfddb0fed650c0
  14:        0x107e18aec - demo::d::h9d9ff8ddd5377da5
  15:        0x107e18ac9 - demo::c::haceeec3fee4323ba
  16:        0x107e18ab9 - demo::b::h4146166847508fc7
  17:        0x107e18aa9 - demo::a::h60d47e17615f49c4
  18:        0x107e18af9 - demo::main::h60dea0663d4b849d
  19:        0x107e18bea - core::ops::function::FnOnce::call_once::hf435db03deecd456
  20:        0x107e189cd - std::sys_common::backtrace::__rust_begin_short_backtrace::h936624db758e7870
  21:        0x107e194d0 - std::rt::lang_start::{{closure}}::ha060b13a4d59d3f5
  22:        0x107e37574 - core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once::h0e377e204feaadc3
                               at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/core/src/ops/function.rs:259:13
  23:        0x107e37574 - std::panicking::try::do_call::h9c5b8eda90bbe0b7
                               at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/std/src/panicking.rs:379:40
  24:        0x107e37574 - std::panicking::try::he150bdff9d5b30f2
                               at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/std/src/panicking.rs:343:19
  25:        0x107e37574 - std::panic::catch_unwind::h04e9c415c0907892
                               at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/std/src/panic.rs:431:14
  26:        0x107e37574 - std::rt::lang_start_internal::h86f505dc7de50d93
                               at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/std/src/rt.rs:51:25
  27:        0x107e194a5 - std::rt::lang_start::h9d080ccd85b4c518
  28:        0x107e18b22 - _main

Which is the full stack trace. However is isn't very usefull as most of it is language internals. Therefor, in the normal mode, rust scans the stack for the __rust_end_short_backtrace and __rust_begin_short_backtrace functions.

These functions dont do anything (hence the trickery to stop them being optimized away), but are rust their for the backtracer to pick up.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM