1 use crate::backtrace_rs
::{self, BacktraceFmt, BytesOrWideString, PrintFmt}
;
2 use crate::borrow
::Cow
;
3 /// Common code for printing the backtrace in the same way across the different
4 /// supported platforms.
8 use crate::io
::prelude
::*;
9 use crate::path
::{self, Path, PathBuf}
;
10 use crate::sync
::atomic
::{self, Ordering}
;
11 use crate::sys_common
::mutex
::StaticMutex
;
13 /// Max number of frames to print.
14 const MAX_NB_FRAMES
: usize = 100;
16 // SAFETY: Don't attempt to lock this reentrantly.
17 pub unsafe fn lock() -> impl Drop
{
18 static LOCK
: StaticMutex
= StaticMutex
::new();
22 /// Prints the current backtrace.
23 pub fn print(w
: &mut dyn Write
, format
: PrintFmt
) -> io
::Result
<()> {
24 // There are issues currently linking libbacktrace into tests, and in
25 // general during libstd's own unit tests we're not testing this path. In
26 // test mode immediately return here to optimize away any references to the
27 // libbacktrace symbols
32 // Use a lock to prevent mixed output in multithreading context.
33 // Some platforms also requires it, like `SymFromAddr` on Windows.
40 unsafe fn _print(w
: &mut dyn Write
, format
: PrintFmt
) -> io
::Result
<()> {
41 struct DisplayBacktrace
{
44 impl fmt
::Display
for DisplayBacktrace
{
45 fn fmt(&self, fmt
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
46 unsafe { _print_fmt(fmt, self.format) }
49 write
!(w
, "{}", DisplayBacktrace { format }
)
52 unsafe fn _print_fmt(fmt
: &mut fmt
::Formatter
<'_
>, print_fmt
: PrintFmt
) -> fmt
::Result
{
53 // Always 'fail' to get the cwd when running under Miri -
54 // this allows Miri to display backtraces in isolation mode
55 let cwd
= if !cfg
!(miri
) { env::current_dir().ok() }
else { None }
;
57 let mut print_path
= move |fmt
: &mut fmt
::Formatter
<'_
>, bows
: BytesOrWideString
<'_
>| {
58 output_filename(fmt
, bows
, print_fmt
, cwd
.as_ref())
60 writeln
!(fmt
, "stack backtrace:")?
;
61 let mut bt_fmt
= BacktraceFmt
::new(fmt
, print_fmt
, &mut print_path
);
62 bt_fmt
.add_context()?
;
65 // Start immediately if we're not using a short backtrace.
66 let mut start
= print_fmt
!= PrintFmt
::Short
;
67 backtrace_rs
::trace_unsynchronized(|frame
| {
68 if print_fmt
== PrintFmt
::Short
&& idx
> MAX_NB_FRAMES
{
74 backtrace_rs
::resolve_frame_unsynchronized(frame
, |symbol
| {
76 if print_fmt
== PrintFmt
::Short
{
77 if let Some(sym
) = symbol
.name().and_then(|s
| s
.as_str()) {
78 if start
&& sym
.contains("__rust_begin_short_backtrace") {
82 if sym
.contains("__rust_end_short_backtrace") {
90 res
= bt_fmt
.frame().symbol(frame
, symbol
);
98 res
= bt_fmt
.frame().print_raw(frame
.ip(), None
, None
, None
);
107 if print_fmt
== PrintFmt
::Short
{
110 "note: Some details are omitted, \
111 run with `RUST_BACKTRACE=full` for a verbose backtrace."
117 /// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that
118 /// this is only inline(never) when backtraces in libstd are enabled, otherwise
119 /// it's fine to optimize away.
120 #[cfg_attr(feature = "backtrace", inline(never))]
121 pub fn __rust_begin_short_backtrace
<F
, T
>(f
: F
) -> T
127 // prevent this frame from being tail-call optimised away
128 crate::hint
::black_box(());
133 /// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that
134 /// this is only inline(never) when backtraces in libstd are enabled, otherwise
135 /// it's fine to optimize away.
136 #[cfg_attr(feature = "backtrace", inline(never))]
137 pub fn __rust_end_short_backtrace
<F
, T
>(f
: F
) -> T
143 // prevent this frame from being tail-call optimised away
144 crate::hint
::black_box(());
149 pub enum RustBacktrace
{
155 // For now logging is turned off by default, and this function checks to see
156 // whether the magical environment variable is present to see if it's turned on.
157 pub fn rust_backtrace_env() -> RustBacktrace
{
158 // If the `backtrace` feature of this crate isn't enabled quickly return
159 // `None` so this can be constant propagated all over the place to turn
160 // optimize away callers.
161 if !cfg
!(feature
= "backtrace") {
162 return RustBacktrace
::Disabled
;
165 // Setting environment variables for Fuchsia components isn't a standard
166 // or easily supported workflow. For now, always display backtraces.
167 if cfg
!(target_os
= "fuchsia") {
168 return RustBacktrace
::Print(PrintFmt
::Full
);
171 static ENABLED
: atomic
::AtomicIsize
= atomic
::AtomicIsize
::new(0);
172 match ENABLED
.load(Ordering
::SeqCst
) {
174 1 => return RustBacktrace
::RuntimeDisabled
,
175 2 => return RustBacktrace
::Print(PrintFmt
::Short
),
176 _
=> return RustBacktrace
::Print(PrintFmt
::Full
),
179 let (format
, cache
) = env
::var_os("RUST_BACKTRACE")
182 (RustBacktrace
::RuntimeDisabled
, 1)
183 } else if &x
== "full" {
184 (RustBacktrace
::Print(PrintFmt
::Full
), 3)
186 (RustBacktrace
::Print(PrintFmt
::Short
), 2)
189 .unwrap_or((RustBacktrace
::RuntimeDisabled
, 1));
190 ENABLED
.store(cache
, Ordering
::SeqCst
);
194 /// Prints the filename of the backtrace frame.
196 /// See also `output`.
197 pub fn output_filename(
198 fmt
: &mut fmt
::Formatter
<'_
>,
199 bows
: BytesOrWideString
<'_
>,
201 cwd
: Option
<&PathBuf
>,
203 let file
: Cow
<'_
, Path
> = match bows
{
205 BytesOrWideString
::Bytes(bytes
) => {
206 use crate::os
::unix
::prelude
::*;
207 Path
::new(crate::ffi
::OsStr
::from_bytes(bytes
)).into()
210 BytesOrWideString
::Bytes(bytes
) => {
211 Path
::new(crate::str::from_utf8(bytes
).unwrap_or("<unknown>")).into()
214 BytesOrWideString
::Wide(wide
) => {
215 use crate::os
::windows
::prelude
::*;
216 Cow
::Owned(crate::ffi
::OsString
::from_wide(wide
).into())
219 BytesOrWideString
::Wide(_wide
) => Path
::new("<unknown>").into(),
221 if print_fmt
== PrintFmt
::Short
&& file
.is_absolute() {
222 if let Some(cwd
) = cwd
{
223 if let Ok(stripped
) = file
.strip_prefix(&cwd
) {
224 if let Some(s
) = stripped
.to_str() {
225 return write
!(fmt
, ".{}{}", path
::MAIN_SEPARATOR
, s
);
230 fmt
::Display
::fmt(&file
.display(), fmt
)