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