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::sys_common
::mutex
::StaticMutex
;
12 /// Max number of frames to print.
13 const MAX_NB_FRAMES
: usize = 100;
15 // SAFETY: Don't attempt to lock this reentrantly.
16 pub unsafe fn lock() -> impl Drop
{
17 static LOCK
: StaticMutex
= StaticMutex
::new();
21 /// Prints the current backtrace.
22 pub fn print(w
: &mut dyn Write
, format
: PrintFmt
) -> io
::Result
<()> {
23 // There are issues currently linking libbacktrace into tests, and in
24 // general during libstd's own unit tests we're not testing this path. In
25 // test mode immediately return here to optimize away any references to the
26 // libbacktrace symbols
31 // Use a lock to prevent mixed output in multithreading context.
32 // Some platforms also requires it, like `SymFromAddr` on Windows.
39 unsafe fn _print(w
: &mut dyn Write
, format
: PrintFmt
) -> io
::Result
<()> {
40 struct DisplayBacktrace
{
43 impl fmt
::Display
for DisplayBacktrace
{
44 fn fmt(&self, fmt
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
45 unsafe { _print_fmt(fmt, self.format) }
48 write
!(w
, "{}", DisplayBacktrace { format }
)
51 unsafe fn _print_fmt(fmt
: &mut fmt
::Formatter
<'_
>, print_fmt
: PrintFmt
) -> fmt
::Result
{
52 // Always 'fail' to get the cwd when running under Miri -
53 // this allows Miri to display backtraces in isolation mode
54 let cwd
= if !cfg
!(miri
) { env::current_dir().ok() }
else { None }
;
56 let mut print_path
= move |fmt
: &mut fmt
::Formatter
<'_
>, bows
: BytesOrWideString
<'_
>| {
57 output_filename(fmt
, bows
, print_fmt
, cwd
.as_ref())
59 writeln
!(fmt
, "stack backtrace:")?
;
60 let mut bt_fmt
= BacktraceFmt
::new(fmt
, print_fmt
, &mut print_path
);
61 bt_fmt
.add_context()?
;
64 // Start immediately if we're not using a short backtrace.
65 let mut start
= print_fmt
!= PrintFmt
::Short
;
66 backtrace_rs
::trace_unsynchronized(|frame
| {
67 if print_fmt
== PrintFmt
::Short
&& idx
> MAX_NB_FRAMES
{
73 backtrace_rs
::resolve_frame_unsynchronized(frame
, |symbol
| {
75 if print_fmt
== PrintFmt
::Short
{
76 if let Some(sym
) = symbol
.name().and_then(|s
| s
.as_str()) {
77 if start
&& sym
.contains("__rust_begin_short_backtrace") {
81 if sym
.contains("__rust_end_short_backtrace") {
89 res
= bt_fmt
.frame().symbol(frame
, symbol
);
96 res
= bt_fmt
.frame().print_raw(frame
.ip(), None
, None
, None
);
104 if print_fmt
== PrintFmt
::Short
{
107 "note: Some details are omitted, \
108 run with `RUST_BACKTRACE=full` for a verbose backtrace."
114 /// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that
115 /// this is only inline(never) when backtraces in libstd are enabled, otherwise
116 /// it's fine to optimize away.
117 #[cfg_attr(feature = "backtrace", inline(never))]
118 pub fn __rust_begin_short_backtrace
<F
, T
>(f
: F
) -> T
124 // prevent this frame from being tail-call optimised away
125 crate::hint
::black_box(());
130 /// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that
131 /// this is only inline(never) when backtraces in libstd are enabled, otherwise
132 /// it's fine to optimize away.
133 #[cfg_attr(feature = "backtrace", inline(never))]
134 pub fn __rust_end_short_backtrace
<F
, T
>(f
: F
) -> T
140 // prevent this frame from being tail-call optimised away
141 crate::hint
::black_box(());
146 /// Prints the filename of the backtrace frame.
148 /// See also `output`.
149 pub fn output_filename(
150 fmt
: &mut fmt
::Formatter
<'_
>,
151 bows
: BytesOrWideString
<'_
>,
153 cwd
: Option
<&PathBuf
>,
155 let file
: Cow
<'_
, Path
> = match bows
{
157 BytesOrWideString
::Bytes(bytes
) => {
158 use crate::os
::unix
::prelude
::*;
159 Path
::new(crate::ffi
::OsStr
::from_bytes(bytes
)).into()
162 BytesOrWideString
::Bytes(bytes
) => {
163 Path
::new(crate::str::from_utf8(bytes
).unwrap_or("<unknown>")).into()
166 BytesOrWideString
::Wide(wide
) => {
167 use crate::os
::windows
::prelude
::*;
168 Cow
::Owned(crate::ffi
::OsString
::from_wide(wide
).into())
171 BytesOrWideString
::Wide(_wide
) => Path
::new("<unknown>").into(),
173 if print_fmt
== PrintFmt
::Short
&& file
.is_absolute() {
174 if let Some(cwd
) = cwd
{
175 if let Ok(stripped
) = file
.strip_prefix(&cwd
) {
176 if let Some(s
) = stripped
.to_str() {
177 return write
!(fmt
, ".{}{s}", path
::MAIN_SEPARATOR
);
182 fmt
::Display
::fmt(&file
.display(), fmt
)