2 pub(crate) use std
::backtrace
::{Backtrace, BacktraceStatus}
;
4 #[cfg(all(not(backtrace), feature = "backtrace"))]
5 pub(crate) use self::capture
::{Backtrace, BacktraceStatus}
;
7 #[cfg(not(any(backtrace, feature = "backtrace")))]
8 pub(crate) enum Backtrace {}
11 macro_rules
! impl_backtrace
{
13 std
::backtrace
::Backtrace
17 #[cfg(all(not(backtrace), feature = "backtrace"))]
18 macro_rules
! impl_backtrace
{
20 impl core
::fmt
::Debug
+ core
::fmt
::Display
24 #[cfg(any(backtrace, feature = "backtrace"))]
25 macro_rules
! backtrace
{
27 Some(crate::backtrace
::Backtrace
::capture())
31 #[cfg(not(any(backtrace, feature = "backtrace")))]
32 macro_rules
! backtrace
{
39 macro_rules
! backtrace_if_absent
{
41 match ($err
as &dyn std
::error
::Error
).request_ref
::<std
::backtrace
::Backtrace
>() {
48 #[cfg(all(feature = "std", not(backtrace), feature = "backtrace"))]
49 macro_rules
! backtrace_if_absent
{
55 #[cfg(all(feature = "std", not(backtrace), not(feature = "backtrace")))]
56 macro_rules
! backtrace_if_absent
{
62 #[cfg(all(not(backtrace), feature = "backtrace"))]
64 use backtrace
::{BacktraceFmt, BytesOrWideString, Frame, PrintFmt, SymbolName}
;
65 use core
::cell
::UnsafeCell
;
66 use core
::fmt
::{self, Debug, Display}
;
67 use core
::sync
::atomic
::{AtomicUsize, Ordering}
;
70 use std
::path
::{self, Path, PathBuf}
;
73 pub(crate) struct Backtrace
{
77 pub(crate) enum BacktraceStatus
{
86 Captured(LazilyResolvedCapture
),
92 frames
: Vec
<BacktraceFrame
>,
95 struct BacktraceFrame
{
97 symbols
: Vec
<BacktraceSymbol
>,
100 struct BacktraceSymbol
{
101 name
: Option
<Vec
<u8>>,
102 filename
: Option
<BytesOrWide
>,
112 impl Debug
for Backtrace
{
113 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
114 let capture
= match &self.inner
{
115 Inner
::Unsupported
=> return fmt
.write_str("<unsupported>"),
116 Inner
::Disabled
=> return fmt
.write_str("<disabled>"),
117 Inner
::Captured(c
) => c
.force(),
120 let frames
= &capture
.frames
[capture
.actual_start
..];
122 write
!(fmt
, "Backtrace ")?
;
124 let mut dbg
= fmt
.debug_list();
126 for frame
in frames
{
127 if frame
.frame
.ip().is_null() {
131 dbg
.entries(&frame
.symbols
);
138 impl Debug
for BacktraceFrame
{
139 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
140 let mut dbg
= fmt
.debug_list();
141 dbg
.entries(&self.symbols
);
146 impl Debug
for BacktraceSymbol
{
147 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
150 if let Some(fn_name
) = self.name
.as_ref().map(|b
| SymbolName
::new(b
)) {
151 write
!(fmt
, "fn: \"{:#}\"", fn_name
)?
;
153 write
!(fmt
, "fn: <unknown>")?
;
156 if let Some(fname
) = self.filename
.as_ref() {
157 write
!(fmt
, ", file: \"{:?}\"", fname
)?
;
160 if let Some(line
) = self.lineno
{
161 write
!(fmt
, ", line: {:?}", line
)?
;
168 impl Debug
for BytesOrWide
{
169 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
173 BytesOrWide
::Bytes(w
) => BytesOrWideString
::Bytes(w
),
174 BytesOrWide
::Wide(w
) => BytesOrWideString
::Wide(w
),
177 env
::current_dir().as_ref().ok(),
183 fn enabled() -> bool
{
184 static ENABLED
: AtomicUsize
= AtomicUsize
::new(0);
185 match ENABLED
.load(Ordering
::Relaxed
) {
190 let enabled
= match env
::var_os("RUST_LIB_BACKTRACE") {
192 None
=> match env
::var_os("RUST_BACKTRACE") {
197 ENABLED
.store(enabled
as usize + 1, Ordering
::Relaxed
);
201 #[inline(never)] // want to make sure there's a frame here to remove
202 pub(crate) fn capture() -> Backtrace
{
203 if Backtrace
::enabled() {
204 Backtrace
::create(Backtrace
::capture
as usize)
206 let inner
= Inner
::Disabled
;
211 // Capture a backtrace which starts just before the function addressed
213 fn create(ip
: usize) -> Backtrace
{
214 let mut frames
= Vec
::new();
215 let mut actual_start
= None
;
216 backtrace
::trace(|frame
| {
217 frames
.push(BacktraceFrame
{
218 frame
: frame
.clone(),
221 if frame
.symbol_address() as usize == ip
&& actual_start
.is_none() {
222 actual_start
= Some(frames
.len() + 1);
227 // If no frames came out assume that this is an unsupported platform
228 // since `backtrace` doesn't provide a way of learning this right
229 // now, and this should be a good enough approximation.
230 let inner
= if frames
.is_empty() {
233 Inner
::Captured(LazilyResolvedCapture
::new(Capture
{
234 actual_start
: actual_start
.unwrap_or(0),
243 pub(crate) fn status(&self) -> BacktraceStatus
{
245 Inner
::Unsupported
=> BacktraceStatus
::Unsupported
,
246 Inner
::Disabled
=> BacktraceStatus
::Disabled
,
247 Inner
::Captured(_
) => BacktraceStatus
::Captured
,
252 impl Display
for Backtrace
{
253 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
254 let capture
= match &self.inner
{
255 Inner
::Unsupported
=> return fmt
.write_str("unsupported backtrace"),
256 Inner
::Disabled
=> return fmt
.write_str("disabled backtrace"),
257 Inner
::Captured(c
) => c
.force(),
260 let full
= fmt
.alternate();
261 let (frames
, style
) = if full
{
262 (&capture
.frames
[..], PrintFmt
::Full
)
264 (&capture
.frames
[capture
.actual_start
..], PrintFmt
::Short
)
267 // When printing paths we try to strip the cwd if it exists,
268 // otherwise we just print the path as-is. Note that we also only do
269 // this for the short format, because if it's full we presumably
270 // want to print everything.
271 let cwd
= env
::current_dir();
272 let mut print_path
= move |fmt
: &mut fmt
::Formatter
, path
: BytesOrWideString
| {
273 output_filename(fmt
, path
, style
, cwd
.as_ref().ok())
276 let mut f
= BacktraceFmt
::new(fmt
, style
, &mut print_path
);
278 for frame
in frames
{
279 let mut f
= f
.frame();
280 if frame
.symbols
.is_empty() {
281 f
.print_raw(frame
.frame
.ip(), None
, None
, None
)?
;
283 for symbol
in frame
.symbols
.iter() {
284 f
.print_raw_with_column(
286 symbol
.name
.as_ref().map(|b
| SymbolName
::new(b
)),
287 symbol
.filename
.as_ref().map(|b
| match b
{
288 BytesOrWide
::Bytes(w
) => BytesOrWideString
::Bytes(w
),
289 BytesOrWide
::Wide(w
) => BytesOrWideString
::Wide(w
),
302 struct LazilyResolvedCapture
{
304 capture
: UnsafeCell
<Capture
>,
307 impl LazilyResolvedCapture
{
308 fn new(capture
: Capture
) -> Self {
309 LazilyResolvedCapture
{
311 capture
: UnsafeCell
::new(capture
),
315 fn force(&self) -> &Capture
{
316 self.sync
.call_once(|| {
317 // Safety: This exclusive reference can't overlap with any
318 // others. `Once` guarantees callers will block until this
319 // closure returns. `Once` also guarantees only a single caller
320 // will enter this closure.
321 unsafe { &mut *self.capture.get() }
.resolve();
324 // Safety: This shared reference can't overlap with the exclusive
326 unsafe { &*self.capture.get() }
330 // Safety: Access to the inner value is synchronized using a thread-safe
331 // `Once`. So long as `Capture` is `Sync`, `LazilyResolvedCapture` is too
332 unsafe impl Sync
for LazilyResolvedCapture
where Capture
: Sync {}
335 fn resolve(&mut self) {
336 // If we're already resolved, nothing to do!
340 self.resolved
= true;
342 for frame
in self.frames
.iter_mut() {
343 let symbols
= &mut frame
.symbols
;
344 let frame
= &frame
.frame
;
345 backtrace
::resolve_frame(frame
, |symbol
| {
346 symbols
.push(BacktraceSymbol
{
347 name
: symbol
.name().map(|m
| m
.as_bytes().to_vec()),
348 filename
: symbol
.filename_raw().map(|b
| match b
{
349 BytesOrWideString
::Bytes(b
) => BytesOrWide
::Bytes(b
.to_owned()),
350 BytesOrWideString
::Wide(b
) => BytesOrWide
::Wide(b
.to_owned()),
352 lineno
: symbol
.lineno(),
353 colno
: symbol
.colno(),
360 // Prints the filename of the backtrace frame.
362 fmt
: &mut fmt
::Formatter
,
363 bows
: BytesOrWideString
,
365 cwd
: Option
<&PathBuf
>,
367 let file
: Cow
<Path
> = match bows
{
369 BytesOrWideString
::Bytes(bytes
) => {
370 use std
::os
::unix
::ffi
::OsStrExt
;
371 Path
::new(std
::ffi
::OsStr
::from_bytes(bytes
)).into()
374 BytesOrWideString
::Bytes(bytes
) => {
375 Path
::new(std
::str::from_utf8(bytes
).unwrap_or("<unknown>")).into()
378 BytesOrWideString
::Wide(wide
) => {
379 use std
::os
::windows
::ffi
::OsStringExt
;
380 Cow
::Owned(std
::ffi
::OsString
::from_wide(wide
).into())
383 BytesOrWideString
::Wide(_wide
) => Path
::new("<unknown>").into(),
385 if print_fmt
== PrintFmt
::Short
&& file
.is_absolute() {
386 if let Some(cwd
) = cwd
{
387 if let Ok(stripped
) = file
.strip_prefix(&cwd
) {
388 if let Some(s
) = stripped
.to_str() {
389 return write
!(fmt
, ".{}{}", path
::MAIN_SEPARATOR
, s
);
394 Display
::fmt(&file
.display(), fmt
)
398 fn _assert_send_sync() {
399 fn _assert
<T
: Send
+ Sync
>() {}
400 _assert
::<Backtrace
>();