1#[cfg(std_backtrace)]
2pub(crate) use std::backtrace::{Backtrace, BacktraceStatus};
3
4#[cfg(all(not(std_backtrace), feature = "backtrace"))]
5pub(crate) use self::capture::{Backtrace, BacktraceStatus};
6
7#[cfg(not(any(std_backtrace, feature = "backtrace")))]
8pub(crate) enum Backtrace {}
9
10#[cfg(std_backtrace)]
11macro_rules! impl_backtrace {
12 () => {
13 std::backtrace::Backtrace
14 };
15}
16
17#[cfg(all(not(std_backtrace), feature = "backtrace"))]
18macro_rules! impl_backtrace {
19 () => {
20 impl core::fmt::Debug + core::fmt::Display
21 };
22}
23
24#[cfg(any(std_backtrace, feature = "backtrace"))]
25macro_rules! backtrace {
26 () => {
27 Some(crate::backtrace::Backtrace::capture())
28 };
29}
30
31#[cfg(not(any(std_backtrace, feature = "backtrace")))]
32macro_rules! backtrace {
33 () => {
34 None
35 };
36}
37
38#[cfg(error_generic_member_access)]
39macro_rules! backtrace_if_absent {
40 ($err:expr) => {
41 match $crate::nightly::request_ref_backtrace($err as &dyn core::error::Error) {
42 Some(_) => None,
43 None => backtrace!(),
44 }
45 };
46}
47
48#[cfg(all(
49 any(feature = "std", not(anyhow_no_core_error)),
50 not(error_generic_member_access),
51 any(std_backtrace, feature = "backtrace")
52))]
53macro_rules! backtrace_if_absent {
54 ($err:expr) => {
55 backtrace!()
56 };
57}
58
59#[cfg(all(
60 any(feature = "std", not(anyhow_no_core_error)),
61 not(std_backtrace),
62 not(feature = "backtrace"),
63))]
64macro_rules! backtrace_if_absent {
65 ($err:expr) => {
66 None
67 };
68}
69
70#[cfg(all(not(std_backtrace), feature = "backtrace"))]
71mod capture {
72 use alloc::borrow::{Cow, ToOwned as _};
73 use alloc::vec::Vec;
74 use backtrace::{BacktraceFmt, BytesOrWideString, Frame, PrintFmt, SymbolName};
75 use core::cell::UnsafeCell;
76 use core::fmt::{self, Debug, Display};
77 use core::sync::atomic::{AtomicUsize, Ordering};
78 use std::env;
79 use std::path::{self, Path, PathBuf};
80 use std::sync::Once;
81
82 pub(crate) struct Backtrace {
83 inner: Inner,
84 }
85
86 pub(crate) enum BacktraceStatus {
87 Unsupported,
88 Disabled,
89 Captured,
90 }
91
92 enum Inner {
93 Unsupported,
94 Disabled,
95 Captured(LazilyResolvedCapture),
96 }
97
98 struct Capture {
99 actual_start: usize,
100 resolved: bool,
101 frames: Vec<BacktraceFrame>,
102 }
103
104 struct BacktraceFrame {
105 frame: Frame,
106 symbols: Vec<BacktraceSymbol>,
107 }
108
109 struct BacktraceSymbol {
110 name: Option<Vec<u8>>,
111 filename: Option<BytesOrWide>,
112 lineno: Option<u32>,
113 colno: Option<u32>,
114 }
115
116 enum BytesOrWide {
117 Bytes(Vec<u8>),
118 Wide(Vec<u16>),
119 }
120
121 impl Debug for Backtrace {
122 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
123 let capture = match &self.inner {
124 Inner::Unsupported => return fmt.write_str("<unsupported>"),
125 Inner::Disabled => return fmt.write_str("<disabled>"),
126 Inner::Captured(c) => c.force(),
127 };
128
129 let frames = &capture.frames[capture.actual_start..];
130
131 write!(fmt, "Backtrace ")?;
132
133 let mut dbg = fmt.debug_list();
134
135 for frame in frames {
136 if frame.frame.ip().is_null() {
137 continue;
138 }
139
140 dbg.entries(&frame.symbols);
141 }
142
143 dbg.finish()
144 }
145 }
146
147 impl Debug for BacktraceFrame {
148 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
149 let mut dbg = fmt.debug_list();
150 dbg.entries(&self.symbols);
151 dbg.finish()
152 }
153 }
154
155 impl Debug for BacktraceSymbol {
156 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
157 write!(fmt, "{{ ")?;
158
159 if let Some(fn_name) = self.name.as_ref().map(|b| SymbolName::new(b)) {
160 write!(fmt, "fn: \"{:#}\"", fn_name)?;
161 } else {
162 write!(fmt, "fn: <unknown>")?;
163 }
164
165 if let Some(fname) = self.filename.as_ref() {
166 write!(fmt, ", file: \"{:?}\"", fname)?;
167 }
168
169 if let Some(line) = self.lineno {
170 write!(fmt, ", line: {:?}", line)?;
171 }
172
173 write!(fmt, " }}")
174 }
175 }
176
177 impl Debug for BytesOrWide {
178 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
179 output_filename(
180 fmt,
181 match self {
182 BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w),
183 BytesOrWide::Wide(w) => BytesOrWideString::Wide(w),
184 },
185 PrintFmt::Short,
186 env::current_dir().as_ref().ok(),
187 )
188 }
189 }
190
191 impl Backtrace {
192 fn enabled() -> bool {
193 static ENABLED: AtomicUsize = AtomicUsize::new(0);
194 match ENABLED.load(Ordering::Relaxed) {
195 0 => {}
196 1 => return false,
197 _ => return true,
198 }
199 let enabled = match env::var_os("RUST_LIB_BACKTRACE") {
200 Some(s) => s != "0",
201 None => match env::var_os("RUST_BACKTRACE") {
202 Some(s) => s != "0",
203 None => false,
204 },
205 };
206 ENABLED.store(enabled as usize + 1, Ordering::Relaxed);
207 enabled
208 }
209
210 #[inline(never)] pub(crate) fn capture() -> Backtrace {
212 if Backtrace::enabled() {
213 Backtrace::create(Backtrace::capture as usize)
214 } else {
215 let inner = Inner::Disabled;
216 Backtrace { inner }
217 }
218 }
219
220 fn create(ip: usize) -> Backtrace {
223 let mut frames = Vec::new();
224 let mut actual_start = None;
225 backtrace::trace(|frame| {
226 frames.push(BacktraceFrame {
227 frame: frame.clone(),
228 symbols: Vec::new(),
229 });
230 if frame.symbol_address() as usize == ip && actual_start.is_none() {
231 actual_start = Some(frames.len() + 1);
232 }
233 true
234 });
235
236 let inner = if frames.is_empty() {
240 Inner::Unsupported
241 } else {
242 Inner::Captured(LazilyResolvedCapture::new(Capture {
243 actual_start: actual_start.unwrap_or(0),
244 frames,
245 resolved: false,
246 }))
247 };
248
249 Backtrace { inner }
250 }
251
252 pub(crate) fn status(&self) -> BacktraceStatus {
253 match self.inner {
254 Inner::Unsupported => BacktraceStatus::Unsupported,
255 Inner::Disabled => BacktraceStatus::Disabled,
256 Inner::Captured(_) => BacktraceStatus::Captured,
257 }
258 }
259 }
260
261 impl Display for Backtrace {
262 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
263 let capture = match &self.inner {
264 Inner::Unsupported => return fmt.write_str("unsupported backtrace"),
265 Inner::Disabled => return fmt.write_str("disabled backtrace"),
266 Inner::Captured(c) => c.force(),
267 };
268
269 let full = fmt.alternate();
270 let (frames, style) = if full {
271 (&capture.frames[..], PrintFmt::Full)
272 } else {
273 (&capture.frames[capture.actual_start..], PrintFmt::Short)
274 };
275
276 let cwd = env::current_dir();
281 let mut print_path = move |fmt: &mut fmt::Formatter, path: BytesOrWideString| {
282 output_filename(fmt, path, style, cwd.as_ref().ok())
283 };
284
285 let mut f = BacktraceFmt::new(fmt, style, &mut print_path);
286 f.add_context()?;
287 for frame in frames {
288 let mut f = f.frame();
289 if frame.symbols.is_empty() {
290 f.print_raw(frame.frame.ip(), None, None, None)?;
291 } else {
292 for symbol in frame.symbols.iter() {
293 f.print_raw_with_column(
294 frame.frame.ip(),
295 symbol.name.as_ref().map(|b| SymbolName::new(b)),
296 symbol.filename.as_ref().map(|b| match b {
297 BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w),
298 BytesOrWide::Wide(w) => BytesOrWideString::Wide(w),
299 }),
300 symbol.lineno,
301 symbol.colno,
302 )?;
303 }
304 }
305 }
306 f.finish()?;
307 Ok(())
308 }
309 }
310
311 struct LazilyResolvedCapture {
312 sync: Once,
313 capture: UnsafeCell<Capture>,
314 }
315
316 impl LazilyResolvedCapture {
317 fn new(capture: Capture) -> Self {
318 LazilyResolvedCapture {
319 sync: Once::new(),
320 capture: UnsafeCell::new(capture),
321 }
322 }
323
324 fn force(&self) -> &Capture {
325 self.sync.call_once(|| {
326 unsafe { &mut *self.capture.get() }.resolve();
331 });
332
333 unsafe { &*self.capture.get() }
336 }
337 }
338
339 unsafe impl Sync for LazilyResolvedCapture where Capture: Sync {}
342
343 impl Capture {
344 fn resolve(&mut self) {
345 if self.resolved {
347 return;
348 }
349 self.resolved = true;
350
351 for frame in self.frames.iter_mut() {
352 let symbols = &mut frame.symbols;
353 let frame = &frame.frame;
354 backtrace::resolve_frame(frame, |symbol| {
355 symbols.push(BacktraceSymbol {
356 name: symbol.name().map(|m| m.as_bytes().to_vec()),
357 filename: symbol.filename_raw().map(|b| match b {
358 BytesOrWideString::Bytes(b) => BytesOrWide::Bytes(b.to_owned()),
359 BytesOrWideString::Wide(b) => BytesOrWide::Wide(b.to_owned()),
360 }),
361 lineno: symbol.lineno(),
362 colno: symbol.colno(),
363 });
364 });
365 }
366 }
367 }
368
369 fn output_filename(
371 fmt: &mut fmt::Formatter,
372 bows: BytesOrWideString,
373 print_fmt: PrintFmt,
374 cwd: Option<&PathBuf>,
375 ) -> fmt::Result {
376 let file: Cow<Path> = match bows {
377 #[cfg(unix)]
378 BytesOrWideString::Bytes(bytes) => {
379 use std::os::unix::ffi::OsStrExt;
380 Path::new(std::ffi::OsStr::from_bytes(bytes)).into()
381 }
382 #[cfg(not(unix))]
383 BytesOrWideString::Bytes(bytes) => {
384 Path::new(std::str::from_utf8(bytes).unwrap_or("<unknown>")).into()
385 }
386 #[cfg(windows)]
387 BytesOrWideString::Wide(wide) => {
388 use std::os::windows::ffi::OsStringExt;
389 Cow::Owned(std::ffi::OsString::from_wide(wide).into())
390 }
391 #[cfg(not(windows))]
392 BytesOrWideString::Wide(_wide) => Path::new("<unknown>").into(),
393 };
394 if print_fmt == PrintFmt::Short && file.is_absolute() {
395 if let Some(cwd) = cwd {
396 if let Ok(stripped) = file.strip_prefix(&cwd) {
397 if let Some(s) = stripped.to_str() {
398 return write!(fmt, ".{}{}", path::MAIN_SEPARATOR, s);
399 }
400 }
401 }
402 }
403 Display::fmt(&file.display(), fmt)
404 }
405}
406
407fn _assert_send_sync() {
408 fn assert<T: Send + Sync>() {}
409 assert::<Backtrace>();
410}