1#![allow(warnings)]
3use std::collections::HashMap;
4use std::hash::{BuildHasher, Hasher};
5use std::panic::Location;
6use std::{cell::RefCell, fmt, fmt::Write, os, path, ptr, sync::Arc, sync::LazyLock};
7
8use backtrace::{BacktraceFmt, BacktraceFrame, BytesOrWideString, Frame};
9
10thread_local! {
11 static FRAMES: RefCell<HashMap<usize, Arc<BacktraceFrame>>> = RefCell::new(HashMap::default());
12 static REPRS: RefCell<HashMap<u64, Arc<str>>> = RefCell::new(HashMap::default());
13 static DEFAULT: Arc<str> = Arc::from("Unresolved backtrace");
14}
15
16static mut START: Option<(&'static str, u32)> = None;
17static mut START_ALT: Option<(&'static str, u32)> = None;
18
19pub fn set_backtrace_start(file: &'static str, line: u32) {
25 unsafe {
26 START = Some((file, line));
27 }
28}
29
30#[doc(hidden)]
31pub fn set_backtrace_start_alt(file: &'static str, line: u32) {
32 unsafe {
33 START_ALT = Some((file, line));
34 }
35}
36
37#[derive(Clone)]
38pub struct Backtrace(Arc<BacktraceRaw>);
44
45#[derive(Debug)]
46pub struct BacktraceResolver {
55 bt: Arc<BacktraceRaw>,
56 repr: Option<Arc<str>>,
57 resolved: bool,
58 frames: HashMap<usize, Arc<BacktraceFrame>>,
59}
60
61#[derive(Debug)]
62pub struct BacktraceRaw {
64 id: u64,
65 frames: [Option<Frame>; 80],
66 location: &'static str,
67}
68
69impl BacktraceRaw {
70 pub fn new(location: &'static Location<'static>) -> Self {
72 Self::with_filename(location.file())
73 }
74
75 #[track_caller]
76 pub fn with_current() -> Self {
78 Self::new(Location::caller())
79 }
80
81 pub fn with_filename(location: &'static str) -> Self {
83 Self::capture(location, |cb| backtrace::trace(cb))
84 }
85
86 #[doc(hidden)]
87 pub unsafe fn with_filename_unsynchronized(location: &'static str) -> Self {
96 Self::capture(location, |cb| unsafe {
97 backtrace::trace_unsynchronized(cb);
98 })
99 }
100
101 fn capture<F>(location: &'static str, trace: F) -> Self
102 where
103 F: FnOnce(&mut dyn FnMut(&Frame) -> bool),
104 {
105 let mut st = foldhash::fast::FixedState::default().build_hasher();
106 let mut idx = 0;
107 let mut frames: [Option<Frame>; 80] = [const { None }; 80];
108
109 trace(&mut |frm| {
110 let ip = frm.ip();
111 st.write_usize(ip as usize);
112 frames[idx] = Some(frm.clone());
113 idx += 1;
114 idx < 80
115 });
116 let id = st.finish();
117
118 BacktraceRaw {
119 id,
120 frames,
121 location,
122 }
123 }
124}
125
126impl From<BacktraceRaw> for Backtrace {
127 fn from(bt: BacktraceRaw) -> Backtrace {
128 Backtrace(Arc::new(bt))
129 }
130}
131
132impl Backtrace {
133 pub fn new(location: &'static Location<'static>) -> Self {
135 Self(Arc::new(BacktraceRaw::new(location)))
136 }
137
138 #[track_caller]
139 pub fn with_current() -> Self {
141 Self(Arc::new(BacktraceRaw::new(Location::caller())))
142 }
143
144 pub fn with_filename(location: &'static str) -> Self {
146 Self(Arc::new(BacktraceRaw::with_filename(location)))
147 }
148
149 pub fn repr(&self) -> Option<Arc<str>> {
151 REPRS.with(|r| r.borrow_mut().get(&self.0.id).cloned())
152 }
153
154 pub fn is_resolved(&self) -> bool {
157 REPRS.with(|r| r.borrow_mut().contains_key(&self.0.id))
158 }
159
160 #[must_use]
162 pub fn resolve(self) -> Self {
163 self.resolver().resolve();
164 self
165 }
166
167 pub fn resolver(&self) -> BacktraceResolver {
171 REPRS.with(|r| {
172 let mut reprs = r.borrow_mut();
173 if let Some(repr) = reprs.get(&self.0.id) {
174 BacktraceResolver {
175 repr: None,
176 resolved: true,
177 bt: self.0.clone(),
178 frames: HashMap::default(),
179 }
180 } else {
181 DEFAULT.with(|s| {
182 reprs.insert(self.0.id, s.clone());
183 });
184
185 let mut frames = HashMap::default();
186
187 FRAMES.with(|c| {
188 let mut cache = c.borrow();
189
190 for frm in &self.0.frames {
191 if let Some(frm) = frm {
192 let ip = frm.ip() as usize;
193 if let Some(frame) = cache.get(&ip) {
194 frames.insert(ip, frame.clone());
195 }
196 }
197 }
198 });
199
200 BacktraceResolver {
201 frames,
202 resolved: false,
203 repr: None,
204 bt: self.0.clone(),
205 }
206 }
207 })
208 }
209}
210
211impl BacktraceResolver {
212 #[allow(clippy::return_self_not_must_use)]
216 pub fn resolve(mut self) -> Self {
217 if self.resolved {
218 return self;
219 }
220
221 for frm in &self.bt.frames {
222 if let Some(frm) = frm {
223 let ip = frm.ip() as usize;
224 if self.frames.contains_key(&ip) {
225 continue;
226 }
227
228 let mut f = BacktraceFrame::from(frm.clone());
229 f.resolve();
230 self.frames.insert(ip, Arc::new(f));
231 }
232 }
233
234 let mut idx = 0;
235 let mut frames: [Option<&BacktraceFrame>; 80] = [None; 80];
236 for frm in &self.bt.frames {
237 if let Some(frm) = frm {
238 let ip = frm.ip() as usize;
239 frames[idx] = Some(self.frames[&ip].as_ref());
240 idx += 1;
241 }
242 }
243
244 find_loc(self.bt.location, &mut frames);
245
246 #[allow(static_mut_refs)]
247 {
248 if let Some(start) = unsafe { START } {
249 find_loc_start(start, &mut frames);
250 }
251 if let Some(start) = unsafe { START_ALT } {
252 find_loc_start(start, &mut frames);
253 }
254 PATHS2.with(|paths| {
255 for s in paths {
256 find_loc_start((s.as_str(), 0), &mut frames);
257 }
258 });
259 }
260
261 let mut idx = 0;
262 for frm in &mut frames {
263 if frm.is_some() {
264 if idx > 10 {
265 *frm = None;
266 } else {
267 idx += 1;
268 }
269 }
270 }
271
272 let bt = Bt(&frames[..]);
273 let mut buf = String::new();
274 let _ = write!(&mut buf, "\n{bt:?}");
275 self.repr = Some(Arc::from(buf));
276
277 self
278 }
279}
280
281impl Drop for BacktraceResolver {
282 fn drop(&mut self) {
283 if !self.resolved {
284 if let Some(repr) = self.repr.take() {
285 REPRS.with(|r| {
286 r.borrow_mut().insert(self.bt.id, repr);
287 });
288 }
289
290 FRAMES.with(|c| {
291 let mut cache = c.borrow_mut();
292
293 for (ip, frm) in &self.frames {
294 let ip = frm.ip() as usize;
295 if !cache.contains_key(&ip) {
296 cache.insert(ip, frm.clone());
297 }
298 }
299 });
300 }
301 }
302}
303
304fn find_loc(loc: &str, frames: &mut [Option<&BacktraceFrame>]) {
305 let mut idx = 0;
306
307 'outter: for (i, frm) in frames.iter().enumerate() {
308 if let Some(f) = frm {
309 for sym in f.symbols() {
310 if let Some(fname) = sym.filename()
311 && fname.ends_with(loc)
312 {
313 idx = i;
314 break 'outter;
315 }
316 }
317 } else {
318 break;
319 }
320 }
321
322 for f in frames.iter_mut().take(idx) {
323 *f = None;
324 }
325
326 PATHS.with(|paths| {
327 'outter: for frm in &mut frames[idx..] {
328 if let Some(f) = frm {
329 for sym in f.symbols() {
330 if let Some(fname) = sym.filename() {
331 for p in paths {
332 if fname.ends_with(p) {
333 *frm = None;
334 continue 'outter;
335 }
336 }
337 }
338 }
339 }
340 }
341 });
342}
343
344thread_local! {
345 static PATHS: Vec<String> = {
346 let mut paths = Vec::new();
347 for item in [
348 &["src", "ctx.rs"][..],
349 &["src", "map_err.rs"][..],
350 &["src", "and_then.rs"][..],
351 &["src", "fn_service.rs"][..],
352 &["src", "pipeline.rs"][..],
353 &["src", "net", "factory.rs"][..],
354 &["src", "future", "future.rs"][..],
355 &["src", "net", "service.rs"][..],
356 &["src", "boxed.rs"][..],
357 &["src", "error.rs"][..],
358 &["src", "wrk.rs"][..],
359 &["src", "future.rs"][..],
360 &["std", "src", "thread", "local.rs"][..],
361 ] {
362 paths.push(item.iter().collect::<path::PathBuf>().to_string_lossy().into_owned());
363 }
364 paths
365 };
366
367 static PATHS2: Vec<String> = {
368 let mut paths = Vec::new();
369 for item in [
370 &["src", "driver.rs"][..],
371 &["src", "rt_compio.rs"][..],
372 &["core", "src", "panic", "unwind_safe.rs"][..],
373 &["src", "runtime", "task", "core.rs"][..]
374 ] {
375 paths.push(item.iter().collect::<path::PathBuf>().to_string_lossy().into_owned());
376 }
377 paths
378 }
379}
380
381fn find_loc_start(loc: (&str, u32), frames: &mut [Option<&BacktraceFrame>]) {
382 let mut idx = 0;
383 while idx < frames.len() {
384 if let Some(frm) = &frames[idx] {
385 for sym in frm.symbols() {
386 if let Some(fname) = sym.filename()
387 && let Some(lineno) = sym.lineno()
388 && fname.ends_with(loc.0)
389 && (loc.1 == 0 || lineno == loc.1)
390 {
391 for f in frames.iter_mut().skip(idx) {
392 if f.is_some() {
393 *f = None;
394 }
395 }
396 return;
397 }
398 }
399 }
400 idx += 1;
401 }
402}
403
404struct Bt<'a>(&'a [Option<&'a BacktraceFrame>]);
405
406impl fmt::Debug for Bt<'_> {
407 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
408 let cwd = std::env::current_dir();
409 let mut print_path = move |fmt: &mut fmt::Formatter<'_>, path: BytesOrWideString<'_>| {
410 let path = crate::utils::module_path_fs(path.to_str_lossy().as_ref());
411 fmt::Display::fmt(&path, fmt)
412 };
413
414 let mut f = BacktraceFmt::new(fmt, backtrace::PrintFmt::Short, &mut print_path);
415 f.add_context()?;
416 for frm in self.0.iter().flatten() {
417 f.frame().backtrace_frame(frm)?;
418 }
419 f.finish()?;
420 Ok(())
421 }
422}
423
424impl fmt::Debug for Backtrace {
425 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
426 if let Some(repr) = self.repr() {
427 fmt::Display::fmt(repr.as_ref(), f)
428 } else {
429 Ok(())
430 }
431 }
432}
433
434impl fmt::Display for Backtrace {
435 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
436 if let Some(repr) = self.repr() {
437 fmt::Display::fmt(repr.as_ref(), f)
438 } else {
439 Ok(())
440 }
441 }
442}