1 /// Common code for printing the backtrace in the same way across the different
2 /// supported platforms.
7 use crate::borrow
::Cow
;
8 use crate::io
::prelude
::*;
9 use crate::path
::{self, Path, PathBuf}
;
10 use crate::sync
::atomic
::{self, Ordering}
;
11 use crate::sys
::mutex
::Mutex
;
13 use backtrace_rs
::{BacktraceFmt, BytesOrWideString, PrintFmt}
;
15 /// Max number of frames to print.
16 const MAX_NB_FRAMES
: usize = 100;
18 pub fn lock() -> impl Drop
{
20 static LOCK
: Mutex
= Mutex
::new();
36 /// Prints the current backtrace.
37 pub fn print(w
: &mut dyn Write
, format
: PrintFmt
) -> io
::Result
<()> {
38 // There are issues currently linking libbacktrace into tests, and in
39 // general during libstd's own unit tests we're not testing this path. In
40 // test mode immediately return here to optimize away any references to the
41 // libbacktrace symbols
46 // Use a lock to prevent mixed output in multithreading context.
47 // Some platforms also requires it, like `SymFromAddr` on Windows.
54 unsafe fn _print(w
: &mut dyn Write
, format
: PrintFmt
) -> io
::Result
<()> {
55 struct DisplayBacktrace
{
58 impl fmt
::Display
for DisplayBacktrace
{
59 fn fmt(&self, fmt
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
61 _print_fmt(fmt
, self.format
)
65 write
!(w
, "{}", DisplayBacktrace { format }
)
68 unsafe fn _print_fmt(fmt
: &mut fmt
::Formatter
<'_
>, print_fmt
: PrintFmt
) -> fmt
::Result
{
69 // Always 'fail' to get the cwd when running under Miri -
70 // this allows Miri to display backtraces in isolation mode
71 let cwd
= if !cfg
!(miri
) {
72 env
::current_dir().ok()
77 let mut print_path
= move |fmt
: &mut fmt
::Formatter
<'_
>, bows
: BytesOrWideString
<'_
>| {
78 output_filename(fmt
, bows
, print_fmt
, cwd
.as_ref())
80 let mut bt_fmt
= BacktraceFmt
::new(fmt
, print_fmt
, &mut print_path
);
81 bt_fmt
.add_context()?
;
84 backtrace_rs
::trace_unsynchronized(|frame
| {
85 if print_fmt
== PrintFmt
::Short
&& idx
> MAX_NB_FRAMES
{
91 backtrace_rs
::resolve_frame_unsynchronized(frame
, |symbol
| {
93 if print_fmt
== PrintFmt
::Short
{
94 if let Some(sym
) = symbol
.name().and_then(|s
| s
.as_str()) {
95 if sym
.contains("__rust_begin_short_backtrace") {
102 res
= bt_fmt
.frame().symbol(frame
, symbol
);
108 res
= bt_fmt
.frame().print_raw(frame
.ip(), None
, None
, None
);
116 if print_fmt
== PrintFmt
::Short
{
119 "note: Some details are omitted, \
120 run with `RUST_BACKTRACE=full` for a verbose backtrace."
126 /// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that
127 /// this is only inline(never) when backtraces in libstd are enabled, otherwise
128 /// it's fine to optimize away.
129 #[cfg_attr(feature = "backtrace", inline(never))]
130 pub fn __rust_begin_short_backtrace
<F
, T
>(f
: F
) -> T
139 pub enum RustBacktrace
{
145 // For now logging is turned off by default, and this function checks to see
146 // whether the magical environment variable is present to see if it's turned on.
147 pub fn rust_backtrace_env() -> RustBacktrace
{
148 // If the `backtrace` feature of this crate isn't enabled quickly return
149 // `None` so this can be constant propagated all over the place to turn
150 // optimize away callers.
151 if !cfg
!(feature
= "backtrace") {
152 return RustBacktrace
::Disabled
;
155 // Setting environment variables for Fuchsia components isn't a standard
156 // or easily supported workflow. For now, always display backtraces.
157 if cfg
!(target_os
= "fuchsia") {
158 return RustBacktrace
::Print(PrintFmt
::Full
);
161 static ENABLED
: atomic
::AtomicIsize
= atomic
::AtomicIsize
::new(0);
162 match ENABLED
.load(Ordering
::SeqCst
) {
164 1 => return RustBacktrace
::RuntimeDisabled
,
165 2 => return RustBacktrace
::Print(PrintFmt
::Short
),
166 _
=> return RustBacktrace
::Print(PrintFmt
::Full
),
169 let (format
, cache
) = env
::var_os("RUST_BACKTRACE")
172 (RustBacktrace
::RuntimeDisabled
, 1)
173 } else if &x
== "full" {
174 (RustBacktrace
::Print(PrintFmt
::Full
), 3)
176 (RustBacktrace
::Print(PrintFmt
::Short
), 2)
179 .unwrap_or((RustBacktrace
::RuntimeDisabled
, 1));
180 ENABLED
.store(cache
, Ordering
::SeqCst
);
184 /// Prints the filename of the backtrace frame.
186 /// See also `output`.
187 pub fn output_filename(
188 fmt
: &mut fmt
::Formatter
<'_
>,
189 bows
: BytesOrWideString
<'_
>,
191 cwd
: Option
<&PathBuf
>,
193 let file
: Cow
<'_
, Path
> = match bows
{
195 BytesOrWideString
::Bytes(bytes
) => {
196 use crate::os
::unix
::prelude
::*;
197 Path
::new(crate::ffi
::OsStr
::from_bytes(bytes
)).into()
200 BytesOrWideString
::Bytes(bytes
) => {
201 Path
::new(crate::str::from_utf8(bytes
).unwrap_or("<unknown>")).into()
204 BytesOrWideString
::Wide(wide
) => {
205 use crate::os
::windows
::prelude
::*;
206 Cow
::Owned(crate::ffi
::OsString
::from_wide(wide
).into())
209 BytesOrWideString
::Wide(_wide
) => {
210 Path
::new("<unknown>").into()
213 if print_fmt
== PrintFmt
::Short
&& file
.is_absolute() {
214 if let Some(cwd
) = cwd
{
215 if let Ok(stripped
) = file
.strip_prefix(&cwd
) {
216 if let Some(s
) = stripped
.to_str() {
217 return write
!(fmt
, ".{}{}", path
::MAIN_SEPARATOR
, s
);
222 fmt
::Display
::fmt(&file
.display(), fmt
)