]> git.proxmox.com Git - rustc.git/blame - library/std/src/sys_common/backtrace.rs
New upstream version 1.68.2+dfsg1
[rustc.git] / library / std / src / sys_common / backtrace.rs
CommitLineData
3dfed10e 1use crate::backtrace_rs::{self, BacktraceFmt, BytesOrWideString, PrintFmt};
dfeec247 2use crate::borrow::Cow;
8bb4bdeb
XL
3/// Common code for printing the backtrace in the same way across the different
4/// supported platforms.
532ac7d7 5use crate::env;
e1599b0c 6use crate::fmt;
532ac7d7 7use crate::io;
dc9dc135 8use crate::io::prelude::*;
e1599b0c 9use crate::path::{self, Path, PathBuf};
2b03887a 10use crate::sync::{Mutex, PoisonError};
532ac7d7 11
8bb4bdeb
XL
12/// Max number of frames to print.
13const MAX_NB_FRAMES: usize = 100;
14
2b03887a
FG
15pub fn lock() -> impl Drop {
16 static LOCK: Mutex<()> = Mutex::new(());
17 LOCK.lock().unwrap_or_else(PoisonError::into_inner)
e1599b0c
XL
18}
19
20/// Prints the current backtrace.
21pub fn print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> {
0731742a 22 // There are issues currently linking libbacktrace into tests, and in
f25598a0 23 // general during std's own unit tests we're not testing this path. In
0731742a
XL
24 // test mode immediately return here to optimize away any references to the
25 // libbacktrace symbols
26 if cfg!(test) {
dc9dc135 27 return Ok(());
0731742a
XL
28 }
29
8bb4bdeb
XL
30 // Use a lock to prevent mixed output in multithreading context.
31 // Some platforms also requires it, like `SymFromAddr` on Windows.
32 unsafe {
e1599b0c
XL
33 let _lock = lock();
34 _print(w, format)
35 }
36}
37
38unsafe fn _print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> {
39 struct DisplayBacktrace {
40 format: PrintFmt,
8bb4bdeb 41 }
e1599b0c
XL
42 impl fmt::Display for DisplayBacktrace {
43 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
dfeec247 44 unsafe { _print_fmt(fmt, self.format) }
e1599b0c
XL
45 }
46 }
47 write!(w, "{}", DisplayBacktrace { format })
8bb4bdeb
XL
48}
49
e1599b0c 50unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::Result {
60c5eb7d
XL
51 // Always 'fail' to get the cwd when running under Miri -
52 // this allows Miri to display backtraces in isolation mode
dfeec247 53 let cwd = if !cfg!(miri) { env::current_dir().ok() } else { None };
60c5eb7d 54
e1599b0c
XL
55 let mut print_path = move |fmt: &mut fmt::Formatter<'_>, bows: BytesOrWideString<'_>| {
56 output_filename(fmt, bows, print_fmt, cwd.as_ref())
57 };
ba9703b0 58 writeln!(fmt, "stack backtrace:")?;
e1599b0c
XL
59 let mut bt_fmt = BacktraceFmt::new(fmt, print_fmt, &mut print_path);
60 bt_fmt.add_context()?;
61 let mut idx = 0;
62 let mut res = Ok(());
3dfed10e
XL
63 // Start immediately if we're not using a short backtrace.
64 let mut start = print_fmt != PrintFmt::Short;
e1599b0c
XL
65 backtrace_rs::trace_unsynchronized(|frame| {
66 if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES {
67 return false;
68 }
8bb4bdeb 69
e1599b0c
XL
70 let mut hit = false;
71 let mut stop = false;
72 backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| {
73 hit = true;
74 if print_fmt == PrintFmt::Short {
75 if let Some(sym) = symbol.name().and_then(|s| s.as_str()) {
94222f64 76 if start && sym.contains("__rust_begin_short_backtrace") {
e1599b0c
XL
77 stop = true;
78 return;
79 }
3dfed10e
XL
80 if sym.contains("__rust_end_short_backtrace") {
81 start = true;
82 return;
83 }
e1599b0c 84 }
7cac9316 85 }
e1599b0c 86
3dfed10e
XL
87 if start {
88 res = bt_fmt.frame().symbol(frame, symbol);
89 }
dc9dc135 90 });
e1599b0c
XL
91 if stop {
92 return false;
93 }
c295e0f8
XL
94 if !hit && start {
95 res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
e1599b0c
XL
96 }
97
98 idx += 1;
99 res.is_ok()
100 });
101 res?;
102 bt_fmt.finish()?;
103 if print_fmt == PrintFmt::Short {
dc9dc135 104 writeln!(
e1599b0c 105 fmt,
dc9dc135
XL
106 "note: Some details are omitted, \
107 run with `RUST_BACKTRACE=full` for a verbose backtrace."
108 )?;
109 }
110 Ok(())
7cac9316
XL
111}
112
e74abb32 113/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that
f25598a0 114/// this is only inline(never) when backtraces in std are enabled, otherwise
e74abb32
XL
115/// it's fine to optimize away.
116#[cfg_attr(feature = "backtrace", inline(never))]
7cac9316 117pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T
dc9dc135
XL
118where
119 F: FnOnce() -> T,
7cac9316 120{
3dfed10e
XL
121 let result = f();
122
123 // prevent this frame from being tail-call optimised away
124 crate::hint::black_box(());
125
126 result
127}
128
129/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that
f25598a0 130/// this is only inline(never) when backtraces in std are enabled, otherwise
3dfed10e
XL
131/// it's fine to optimize away.
132#[cfg_attr(feature = "backtrace", inline(never))]
133pub fn __rust_end_short_backtrace<F, T>(f: F) -> T
134where
135 F: FnOnce() -> T,
136{
137 let result = f();
138
139 // prevent this frame from being tail-call optimised away
140 crate::hint::black_box(());
141
142 result
8bb4bdeb
XL
143}
144
e1599b0c
XL
145/// Prints the filename of the backtrace frame.
146///
147/// See also `output`.
148pub fn output_filename(
149 fmt: &mut fmt::Formatter<'_>,
150 bows: BytesOrWideString<'_>,
151 print_fmt: PrintFmt,
152 cwd: Option<&PathBuf>,
153) -> fmt::Result {
154 let file: Cow<'_, Path> = match bows {
155 #[cfg(unix)]
156 BytesOrWideString::Bytes(bytes) => {
157 use crate::os::unix::prelude::*;
158 Path::new(crate::ffi::OsStr::from_bytes(bytes)).into()
8bb4bdeb 159 }
e1599b0c
XL
160 #[cfg(not(unix))]
161 BytesOrWideString::Bytes(bytes) => {
162 Path::new(crate::str::from_utf8(bytes).unwrap_or("<unknown>")).into()
dc9dc135 163 }
dc9dc135 164 #[cfg(windows)]
e1599b0c
XL
165 BytesOrWideString::Wide(wide) => {
166 use crate::os::windows::prelude::*;
167 Cow::Owned(crate::ffi::OsString::from_wide(wide).into())
dc9dc135 168 }
e1599b0c 169 #[cfg(not(windows))]
dfeec247 170 BytesOrWideString::Wide(_wide) => Path::new("<unknown>").into(),
e1599b0c
XL
171 };
172 if print_fmt == PrintFmt::Short && file.is_absolute() {
173 if let Some(cwd) = cwd {
174 if let Ok(stripped) = file.strip_prefix(&cwd) {
175 if let Some(s) = stripped.to_str() {
5e7ed085 176 return write!(fmt, ".{}{s}", path::MAIN_SEPARATOR);
dc9dc135
XL
177 }
178 }
179 }
dc9dc135 180 }
e1599b0c 181 fmt::Display::fmt(&file.display(), fmt)
e9174d1e 182}