[英]How does __rust_begin_short_backtrace work in Rust?
如题。
我知道__rust_begin_short_backtrace
用于堆栈回溯,但它实际上是如何工作的? 我发现它的实现真的很短,就像下面一样。 它所做的只是间接调用传入的 function,并返回结果。 我还发现对应的 function __rust_end_short_backtrace
具有完全相同的实现。 代码位于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
}
相关实现的另一部分也在“ library/std/src/sys_common/backtrace.rs ”。 下面是这部分的一段代码,我认为是高度相关和重要的,但我不明白 Rust 如何处理与前两个函数相关的符号的逻辑:
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 正在插入这些“虚拟符号”以允许短回溯。
考虑这段代码
fn a() {
b()
}
fn b() {
c()
}
fn c() {
d()
}
fn d() {
panic!()
}
fn main() {
a()
}
这提供了一个很好的回溯
$ 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.
如果我们改为使用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
这是完整的堆栈跟踪。 然而,它并不是很有用,因为它大部分是语言内部的。 因此,在正常模式下,rust 会扫描堆栈以__rust_end_short_backtrace
和__rust_begin_short_backtrace
函数。
这些函数不做任何事情(因此阻止它们被优化掉的诡计),但是 rust 它们是供回溯器拾取的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.