std/sys/
backtrace.rs
1#![forbid(unsafe_op_in_unsafe_fn)]
3
4use crate::backtrace_rs::{self, BacktraceFmt, BytesOrWideString, PrintFmt};
5use crate::borrow::Cow;
6use crate::io::prelude::*;
7use crate::path::{self, Path, PathBuf};
8use crate::sync::{Mutex, MutexGuard, PoisonError};
9use crate::{env, fmt, io};
10
11const MAX_NB_FRAMES: usize = 100;
13
14pub(crate) struct BacktraceLock<'a>(#[allow(dead_code)] MutexGuard<'a, ()>);
15
16pub(crate) fn lock<'a>() -> BacktraceLock<'a> {
17 static LOCK: Mutex<()> = Mutex::new(());
18 BacktraceLock(LOCK.lock().unwrap_or_else(PoisonError::into_inner))
19}
20
21impl BacktraceLock<'_> {
22 pub(crate) fn print(&mut self, w: &mut dyn Write, format: PrintFmt) -> io::Result<()> {
26 if cfg!(test) {
31 return Ok(());
32 }
33
34 struct DisplayBacktrace {
35 format: PrintFmt,
36 }
37 impl fmt::Display for DisplayBacktrace {
38 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
39 unsafe { _print_fmt(fmt, self.format) }
40 }
41 }
42 write!(w, "{}", DisplayBacktrace { format })
43 }
44}
45
46unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::Result {
47 let cwd = if !cfg!(miri) { env::current_dir().ok() } else { None };
50
51 let mut print_path = move |fmt: &mut fmt::Formatter<'_>, bows: BytesOrWideString<'_>| {
52 output_filename(fmt, bows, print_fmt, cwd.as_ref())
53 };
54 writeln!(fmt, "stack backtrace:")?;
55 let mut bt_fmt = BacktraceFmt::new(fmt, print_fmt, &mut print_path);
56 bt_fmt.add_context()?;
57 let mut idx = 0;
58 let mut res = Ok(());
59 let mut omitted_count: usize = 0;
60 let mut first_omit = true;
61 let mut print = print_fmt != PrintFmt::Short;
63 set_image_base();
64 unsafe {
66 backtrace_rs::trace_unsynchronized(|frame| {
67 if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES {
68 return false;
69 }
70
71 if cfg!(feature = "backtrace-trace-only") {
72 const HEX_WIDTH: usize = 2 + 2 * size_of::<usize>();
73 let frame_ip = frame.ip();
74 res = writeln!(bt_fmt.formatter(), "{idx:4}: {frame_ip:HEX_WIDTH$?}");
75 } else {
76 let mut hit = false;
77 backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| {
78 hit = true;
79
80 if print_fmt == PrintFmt::Short {
83 if let Some(sym) = symbol.name().and_then(|s| s.as_str()) {
84 if sym.contains("__rust_end_short_backtrace") {
85 print = true;
86 return;
87 }
88 if print && sym.contains("__rust_begin_short_backtrace") {
89 print = false;
90 return;
91 }
92 if !print {
93 omitted_count += 1;
94 }
95 }
96 }
97
98 if print {
99 if omitted_count > 0 {
100 debug_assert!(print_fmt == PrintFmt::Short);
101 if !first_omit {
103 let _ = writeln!(
104 bt_fmt.formatter(),
105 " [... omitted {} frame{} ...]",
106 omitted_count,
107 if omitted_count > 1 { "s" } else { "" }
108 );
109 }
110 first_omit = false;
111 omitted_count = 0;
112 }
113 res = bt_fmt.frame().symbol(frame, symbol);
114 }
115 });
116 #[cfg(target_os = "nto")]
117 if libc::__my_thread_exit as *mut libc::c_void == frame.ip() {
118 if !hit && print {
119 use crate::backtrace_rs::SymbolName;
120 res = bt_fmt.frame().print_raw(
121 frame.ip(),
122 Some(SymbolName::new("__my_thread_exit".as_bytes())),
123 None,
124 None,
125 );
126 }
127 return false;
128 }
129 if !hit && print {
130 res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
131 }
132 }
133
134 idx += 1;
135 res.is_ok()
136 })
137 };
138 res?;
139 bt_fmt.finish()?;
140 if print_fmt == PrintFmt::Short {
141 writeln!(
142 fmt,
143 "note: Some details are omitted, \
144 run with `RUST_BACKTRACE=full` for a verbose backtrace."
145 )?;
146 }
147 Ok(())
148}
149
150#[cfg_attr(feature = "backtrace", inline(never))]
154pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T
155where
156 F: FnOnce() -> T,
157{
158 let result = f();
159
160 crate::hint::black_box(());
162
163 result
164}
165
166#[cfg_attr(feature = "backtrace", inline(never))]
170pub fn __rust_end_short_backtrace<F, T>(f: F) -> T
171where
172 F: FnOnce() -> T,
173{
174 let result = f();
175
176 crate::hint::black_box(());
178
179 result
180}
181
182pub fn output_filename(
186 fmt: &mut fmt::Formatter<'_>,
187 bows: BytesOrWideString<'_>,
188 print_fmt: PrintFmt,
189 cwd: Option<&PathBuf>,
190) -> fmt::Result {
191 let file: Cow<'_, Path> = match bows {
192 #[cfg(unix)]
193 BytesOrWideString::Bytes(bytes) => {
194 use crate::os::unix::prelude::*;
195 Path::new(crate::ffi::OsStr::from_bytes(bytes)).into()
196 }
197 #[cfg(not(unix))]
198 BytesOrWideString::Bytes(bytes) => {
199 Path::new(crate::str::from_utf8(bytes).unwrap_or("<unknown>")).into()
200 }
201 #[cfg(windows)]
202 BytesOrWideString::Wide(wide) => {
203 use crate::os::windows::prelude::*;
204 Cow::Owned(crate::ffi::OsString::from_wide(wide).into())
205 }
206 #[cfg(not(windows))]
207 BytesOrWideString::Wide(_wide) => Path::new("<unknown>").into(),
208 };
209 if print_fmt == PrintFmt::Short && file.is_absolute() {
210 if let Some(cwd) = cwd {
211 if let Ok(stripped) = file.strip_prefix(&cwd) {
212 if let Some(s) = stripped.to_str() {
213 return write!(fmt, ".{}{s}", path::MAIN_SEPARATOR);
214 }
215 }
216 }
217 }
218 fmt::Display::fmt(&file.display(), fmt)
219}
220
221#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
222pub fn set_image_base() {
223 let image_base = crate::os::fortanix_sgx::mem::image_base();
224 backtrace_rs::set_image_base(crate::ptr::without_provenance_mut(image_base as _));
225}
226
227#[cfg(not(all(target_vendor = "fortanix", target_env = "sgx")))]
228pub fn set_image_base() {
229 }