xref: /aosp_15_r20/external/cronet/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.82/src/backtrace.rs (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 #[cfg(std_backtrace)]
2 pub(crate) use std::backtrace::{Backtrace, BacktraceStatus};
3 
4 #[cfg(all(not(std_backtrace), feature = "backtrace"))]
5 pub(crate) use self::capture::{Backtrace, BacktraceStatus};
6 
7 #[cfg(not(any(std_backtrace, feature = "backtrace")))]
8 pub(crate) enum Backtrace {}
9 
10 #[cfg(std_backtrace)]
11 macro_rules! impl_backtrace {
12     () => {
13         std::backtrace::Backtrace
14     };
15 }
16 
17 #[cfg(all(not(std_backtrace), feature = "backtrace"))]
18 macro_rules! impl_backtrace {
19     () => {
20         impl core::fmt::Debug + core::fmt::Display
21     };
22 }
23 
24 #[cfg(any(std_backtrace, feature = "backtrace"))]
25 macro_rules! backtrace {
26     () => {
27         Some(crate::backtrace::Backtrace::capture())
28     };
29 }
30 
31 #[cfg(not(any(std_backtrace, feature = "backtrace")))]
32 macro_rules! backtrace {
33     () => {
34         None
35     };
36 }
37 
38 #[cfg(error_generic_member_access)]
39 macro_rules! backtrace_if_absent {
40     ($err:expr) => {
41         match std::error::request_ref::<std::backtrace::Backtrace>($err as &dyn std::error::Error) {
42             Some(_) => None,
43             None => backtrace!(),
44         }
45     };
46 }
47 
48 #[cfg(all(
49     feature = "std",
50     not(error_generic_member_access),
51     any(std_backtrace, feature = "backtrace")
52 ))]
53 macro_rules! backtrace_if_absent {
54     ($err:expr) => {
55         backtrace!()
56     };
57 }
58 
59 #[cfg(all(feature = "std", not(std_backtrace), not(feature = "backtrace")))]
60 macro_rules! backtrace_if_absent {
61     ($err:expr) => {
62         None
63     };
64 }
65 
66 #[cfg(all(not(std_backtrace), feature = "backtrace"))]
67 mod capture {
68     use alloc::borrow::{Cow, ToOwned as _};
69     use alloc::vec::Vec;
70     use backtrace::{BacktraceFmt, BytesOrWideString, Frame, PrintFmt, SymbolName};
71     use core::cell::UnsafeCell;
72     use core::fmt::{self, Debug, Display};
73     use core::sync::atomic::{AtomicUsize, Ordering};
74     use std::env;
75     use std::path::{self, Path, PathBuf};
76     use std::sync::Once;
77 
78     pub(crate) struct Backtrace {
79         inner: Inner,
80     }
81 
82     pub(crate) enum BacktraceStatus {
83         Unsupported,
84         Disabled,
85         Captured,
86     }
87 
88     enum Inner {
89         Unsupported,
90         Disabled,
91         Captured(LazilyResolvedCapture),
92     }
93 
94     struct Capture {
95         actual_start: usize,
96         resolved: bool,
97         frames: Vec<BacktraceFrame>,
98     }
99 
100     struct BacktraceFrame {
101         frame: Frame,
102         symbols: Vec<BacktraceSymbol>,
103     }
104 
105     struct BacktraceSymbol {
106         name: Option<Vec<u8>>,
107         filename: Option<BytesOrWide>,
108         lineno: Option<u32>,
109         colno: Option<u32>,
110     }
111 
112     enum BytesOrWide {
113         Bytes(Vec<u8>),
114         Wide(Vec<u16>),
115     }
116 
117     impl Debug for Backtrace {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result118         fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
119             let capture = match &self.inner {
120                 Inner::Unsupported => return fmt.write_str("<unsupported>"),
121                 Inner::Disabled => return fmt.write_str("<disabled>"),
122                 Inner::Captured(c) => c.force(),
123             };
124 
125             let frames = &capture.frames[capture.actual_start..];
126 
127             write!(fmt, "Backtrace ")?;
128 
129             let mut dbg = fmt.debug_list();
130 
131             for frame in frames {
132                 if frame.frame.ip().is_null() {
133                     continue;
134                 }
135 
136                 dbg.entries(&frame.symbols);
137             }
138 
139             dbg.finish()
140         }
141     }
142 
143     impl Debug for BacktraceFrame {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result144         fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
145             let mut dbg = fmt.debug_list();
146             dbg.entries(&self.symbols);
147             dbg.finish()
148         }
149     }
150 
151     impl Debug for BacktraceSymbol {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result152         fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
153             write!(fmt, "{{ ")?;
154 
155             if let Some(fn_name) = self.name.as_ref().map(|b| SymbolName::new(b)) {
156                 write!(fmt, "fn: \"{:#}\"", fn_name)?;
157             } else {
158                 write!(fmt, "fn: <unknown>")?;
159             }
160 
161             if let Some(fname) = self.filename.as_ref() {
162                 write!(fmt, ", file: \"{:?}\"", fname)?;
163             }
164 
165             if let Some(line) = self.lineno {
166                 write!(fmt, ", line: {:?}", line)?;
167             }
168 
169             write!(fmt, " }}")
170         }
171     }
172 
173     impl Debug for BytesOrWide {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result174         fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
175             output_filename(
176                 fmt,
177                 match self {
178                     BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w),
179                     BytesOrWide::Wide(w) => BytesOrWideString::Wide(w),
180                 },
181                 PrintFmt::Short,
182                 env::current_dir().as_ref().ok(),
183             )
184         }
185     }
186 
187     impl Backtrace {
enabled() -> bool188         fn enabled() -> bool {
189             static ENABLED: AtomicUsize = AtomicUsize::new(0);
190             match ENABLED.load(Ordering::Relaxed) {
191                 0 => {}
192                 1 => return false,
193                 _ => return true,
194             }
195             let enabled = match env::var_os("RUST_LIB_BACKTRACE") {
196                 Some(s) => s != "0",
197                 None => match env::var_os("RUST_BACKTRACE") {
198                     Some(s) => s != "0",
199                     None => false,
200                 },
201             };
202             ENABLED.store(enabled as usize + 1, Ordering::Relaxed);
203             enabled
204         }
205 
206         #[inline(never)] // want to make sure there's a frame here to remove
capture() -> Backtrace207         pub(crate) fn capture() -> Backtrace {
208             if Backtrace::enabled() {
209                 Backtrace::create(Backtrace::capture as usize)
210             } else {
211                 let inner = Inner::Disabled;
212                 Backtrace { inner }
213             }
214         }
215 
216         // Capture a backtrace which starts just before the function addressed
217         // by `ip`
create(ip: usize) -> Backtrace218         fn create(ip: usize) -> Backtrace {
219             let mut frames = Vec::new();
220             let mut actual_start = None;
221             backtrace::trace(|frame| {
222                 frames.push(BacktraceFrame {
223                     frame: frame.clone(),
224                     symbols: Vec::new(),
225                 });
226                 if frame.symbol_address() as usize == ip && actual_start.is_none() {
227                     actual_start = Some(frames.len() + 1);
228                 }
229                 true
230             });
231 
232             // If no frames came out assume that this is an unsupported platform
233             // since `backtrace` doesn't provide a way of learning this right
234             // now, and this should be a good enough approximation.
235             let inner = if frames.is_empty() {
236                 Inner::Unsupported
237             } else {
238                 Inner::Captured(LazilyResolvedCapture::new(Capture {
239                     actual_start: actual_start.unwrap_or(0),
240                     frames,
241                     resolved: false,
242                 }))
243             };
244 
245             Backtrace { inner }
246         }
247 
status(&self) -> BacktraceStatus248         pub(crate) fn status(&self) -> BacktraceStatus {
249             match self.inner {
250                 Inner::Unsupported => BacktraceStatus::Unsupported,
251                 Inner::Disabled => BacktraceStatus::Disabled,
252                 Inner::Captured(_) => BacktraceStatus::Captured,
253             }
254         }
255     }
256 
257     impl Display for Backtrace {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result258         fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
259             let capture = match &self.inner {
260                 Inner::Unsupported => return fmt.write_str("unsupported backtrace"),
261                 Inner::Disabled => return fmt.write_str("disabled backtrace"),
262                 Inner::Captured(c) => c.force(),
263             };
264 
265             let full = fmt.alternate();
266             let (frames, style) = if full {
267                 (&capture.frames[..], PrintFmt::Full)
268             } else {
269                 (&capture.frames[capture.actual_start..], PrintFmt::Short)
270             };
271 
272             // When printing paths we try to strip the cwd if it exists,
273             // otherwise we just print the path as-is. Note that we also only do
274             // this for the short format, because if it's full we presumably
275             // want to print everything.
276             let cwd = env::current_dir();
277             let mut print_path = move |fmt: &mut fmt::Formatter, path: BytesOrWideString| {
278                 output_filename(fmt, path, style, cwd.as_ref().ok())
279             };
280 
281             let mut f = BacktraceFmt::new(fmt, style, &mut print_path);
282             f.add_context()?;
283             for frame in frames {
284                 let mut f = f.frame();
285                 if frame.symbols.is_empty() {
286                     f.print_raw(frame.frame.ip(), None, None, None)?;
287                 } else {
288                     for symbol in frame.symbols.iter() {
289                         f.print_raw_with_column(
290                             frame.frame.ip(),
291                             symbol.name.as_ref().map(|b| SymbolName::new(b)),
292                             symbol.filename.as_ref().map(|b| match b {
293                                 BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w),
294                                 BytesOrWide::Wide(w) => BytesOrWideString::Wide(w),
295                             }),
296                             symbol.lineno,
297                             symbol.colno,
298                         )?;
299                     }
300                 }
301             }
302             f.finish()?;
303             Ok(())
304         }
305     }
306 
307     struct LazilyResolvedCapture {
308         sync: Once,
309         capture: UnsafeCell<Capture>,
310     }
311 
312     impl LazilyResolvedCapture {
new(capture: Capture) -> Self313         fn new(capture: Capture) -> Self {
314             LazilyResolvedCapture {
315                 sync: Once::new(),
316                 capture: UnsafeCell::new(capture),
317             }
318         }
319 
force(&self) -> &Capture320         fn force(&self) -> &Capture {
321             self.sync.call_once(|| {
322                 // Safety: This exclusive reference can't overlap with any
323                 // others. `Once` guarantees callers will block until this
324                 // closure returns. `Once` also guarantees only a single caller
325                 // will enter this closure.
326                 unsafe { &mut *self.capture.get() }.resolve();
327             });
328 
329             // Safety: This shared reference can't overlap with the exclusive
330             // reference above.
331             unsafe { &*self.capture.get() }
332         }
333     }
334 
335     // Safety: Access to the inner value is synchronized using a thread-safe
336     // `Once`. So long as `Capture` is `Sync`, `LazilyResolvedCapture` is too
337     unsafe impl Sync for LazilyResolvedCapture where Capture: Sync {}
338 
339     impl Capture {
resolve(&mut self)340         fn resolve(&mut self) {
341             // If we're already resolved, nothing to do!
342             if self.resolved {
343                 return;
344             }
345             self.resolved = true;
346 
347             for frame in self.frames.iter_mut() {
348                 let symbols = &mut frame.symbols;
349                 let frame = &frame.frame;
350                 backtrace::resolve_frame(frame, |symbol| {
351                     symbols.push(BacktraceSymbol {
352                         name: symbol.name().map(|m| m.as_bytes().to_vec()),
353                         filename: symbol.filename_raw().map(|b| match b {
354                             BytesOrWideString::Bytes(b) => BytesOrWide::Bytes(b.to_owned()),
355                             BytesOrWideString::Wide(b) => BytesOrWide::Wide(b.to_owned()),
356                         }),
357                         lineno: symbol.lineno(),
358                         colno: symbol.colno(),
359                     });
360                 });
361             }
362         }
363     }
364 
365     // Prints the filename of the backtrace frame.
output_filename( fmt: &mut fmt::Formatter, bows: BytesOrWideString, print_fmt: PrintFmt, cwd: Option<&PathBuf>, ) -> fmt::Result366     fn output_filename(
367         fmt: &mut fmt::Formatter,
368         bows: BytesOrWideString,
369         print_fmt: PrintFmt,
370         cwd: Option<&PathBuf>,
371     ) -> fmt::Result {
372         let file: Cow<Path> = match bows {
373             #[cfg(unix)]
374             BytesOrWideString::Bytes(bytes) => {
375                 use std::os::unix::ffi::OsStrExt;
376                 Path::new(std::ffi::OsStr::from_bytes(bytes)).into()
377             }
378             #[cfg(not(unix))]
379             BytesOrWideString::Bytes(bytes) => {
380                 Path::new(std::str::from_utf8(bytes).unwrap_or("<unknown>")).into()
381             }
382             #[cfg(windows)]
383             BytesOrWideString::Wide(wide) => {
384                 use std::os::windows::ffi::OsStringExt;
385                 Cow::Owned(std::ffi::OsString::from_wide(wide).into())
386             }
387             #[cfg(not(windows))]
388             BytesOrWideString::Wide(_wide) => Path::new("<unknown>").into(),
389         };
390         if print_fmt == PrintFmt::Short && file.is_absolute() {
391             if let Some(cwd) = cwd {
392                 if let Ok(stripped) = file.strip_prefix(&cwd) {
393                     if let Some(s) = stripped.to_str() {
394                         return write!(fmt, ".{}{}", path::MAIN_SEPARATOR, s);
395                     }
396                 }
397             }
398         }
399         Display::fmt(&file.display(), fmt)
400     }
401 }
402 
_assert_send_sync()403 fn _assert_send_sync() {
404     fn _assert<T: Send + Sync>() {}
405     _assert::<Backtrace>();
406 }
407