1#![allow(warnings)]
3use std::collections::HashMap;
4use std::hash::{BuildHasher, Hasher};
5use std::panic::Location;
6use std::{cell::RefCell, ffi::c_void, fmt, fmt::Write, os, path, ptr, sync::Arc, sync::LazyLock};
7
8use backtrace::{BacktraceFmt, BytesOrWideString, Frame, SymbolName};
9
10thread_local! {
11 static FRAMES: RefCell<HashMap<usize, Arc<ResolvedFrame>>> = 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<ResolvedFrame>>,
59}
60
61#[derive(Debug)]
62pub struct BacktraceRaw {
64 id: u64,
65 frames: [Option<RawFrame>; 80],
66 location: &'static str,
67}
68
69#[derive(Debug, Clone)]
70enum RawFrame {
71 Frame(Frame),
72 Ip(usize),
73}
74
75impl RawFrame {
76 fn ip(&self) -> usize {
77 match self {
78 RawFrame::Frame(frm) => frm.ip() as usize,
79 RawFrame::Ip(ip) => *ip,
80 }
81 }
82}
83
84#[derive(Debug)]
85struct ResolvedFrame {
86 ip: usize,
87 symbols: Vec<ResolvedSymbol>,
88}
89
90#[derive(Debug)]
91struct ResolvedSymbol {
92 name: Option<Vec<u8>>,
93 filename: Option<path::PathBuf>,
94 lineno: Option<u32>,
95 colno: Option<u32>,
96}
97
98impl ResolvedFrame {
99 fn resolve(frm: &RawFrame) -> Self {
100 let mut symbols = Vec::new();
101 let mut cb = |sym: &backtrace::Symbol| {
102 symbols.push(ResolvedSymbol {
103 name: sym.name().map(|n| n.as_bytes().to_vec()),
104 filename: sym.filename().map(path::Path::to_path_buf),
105 lineno: sym.lineno(),
106 colno: sym.colno(),
107 });
108 };
109 match frm {
110 RawFrame::Frame(f) => backtrace::resolve_frame(f, &mut cb),
111 RawFrame::Ip(ip) => backtrace::resolve(*ip as *mut c_void, &mut cb),
112 }
113 ResolvedFrame {
114 ip: frm.ip(),
115 symbols,
116 }
117 }
118}
119
120impl BacktraceRaw {
121 pub fn new(location: &'static Location<'static>) -> Self {
123 Self::with_filename(location.file())
124 }
125
126 #[track_caller]
127 pub fn with_current() -> Self {
129 Self::new(Location::caller())
130 }
131
132 pub fn with_filename(location: &'static str) -> Self {
134 Self::capture(location, |cb| backtrace::trace(cb))
135 }
136
137 #[doc(hidden)]
138 pub unsafe fn with_filename_unsynchronized(location: &'static str) -> Self {
147 Self::capture(location, |cb| unsafe {
148 backtrace::trace_unsynchronized(cb);
149 })
150 }
151
152 #[doc(hidden)]
153 pub fn from_ips(ips: &[usize], location: &'static str) -> Self {
158 let mut st = foldhash::fast::FixedState::default().build_hasher();
159 let mut frames: [Option<RawFrame>; 80] = [const { None }; 80];
160
161 for (frm, ip) in frames.iter_mut().zip(ips) {
162 st.write_usize(*ip);
163 *frm = Some(RawFrame::Ip(*ip));
164 }
165 let id = st.finish();
166
167 BacktraceRaw {
168 id,
169 frames,
170 location,
171 }
172 }
173
174 fn capture<F>(location: &'static str, trace: F) -> Self
175 where
176 F: FnOnce(&mut dyn FnMut(&Frame) -> bool),
177 {
178 let mut st = foldhash::fast::FixedState::default().build_hasher();
179 let mut idx = 0;
180 let mut frames: [Option<RawFrame>; 80] = [const { None }; 80];
181
182 trace(&mut |frm| {
183 let ip = frm.ip();
184 st.write_usize(ip as usize);
185 frames[idx] = Some(RawFrame::Frame(frm.clone()));
186 idx += 1;
187 idx < 80
188 });
189 let id = st.finish();
190
191 BacktraceRaw {
192 id,
193 frames,
194 location,
195 }
196 }
197}
198
199impl From<BacktraceRaw> for Backtrace {
200 fn from(bt: BacktraceRaw) -> Backtrace {
201 Backtrace(Arc::new(bt))
202 }
203}
204
205impl Backtrace {
206 pub fn new(location: &'static Location<'static>) -> Self {
208 Self(Arc::new(BacktraceRaw::new(location)))
209 }
210
211 #[track_caller]
212 pub fn with_current() -> Self {
214 Self(Arc::new(BacktraceRaw::new(Location::caller())))
215 }
216
217 pub fn with_filename(location: &'static str) -> Self {
219 Self(Arc::new(BacktraceRaw::with_filename(location)))
220 }
221
222 pub fn repr(&self) -> Option<Arc<str>> {
224 REPRS.with(|r| r.borrow_mut().get(&self.0.id).cloned())
225 }
226
227 pub fn is_resolved(&self) -> bool {
230 REPRS.with(|r| r.borrow_mut().contains_key(&self.0.id))
231 }
232
233 #[must_use]
235 pub fn resolve(self) -> Self {
236 self.resolver().resolve();
237 self
238 }
239
240 pub fn resolver(&self) -> BacktraceResolver {
244 REPRS.with(|r| {
245 let mut reprs = r.borrow_mut();
246 if let Some(repr) = reprs.get(&self.0.id) {
247 BacktraceResolver {
248 repr: None,
249 resolved: true,
250 bt: self.0.clone(),
251 frames: HashMap::default(),
252 }
253 } else {
254 DEFAULT.with(|s| {
255 reprs.insert(self.0.id, s.clone());
256 });
257
258 let mut frames = HashMap::default();
259
260 FRAMES.with(|c| {
261 let mut cache = c.borrow();
262
263 for frm in &self.0.frames {
264 if let Some(frm) = frm {
265 let ip = frm.ip();
266 if let Some(frame) = cache.get(&ip) {
267 frames.insert(ip, frame.clone());
268 }
269 }
270 }
271 });
272
273 BacktraceResolver {
274 frames,
275 resolved: false,
276 repr: None,
277 bt: self.0.clone(),
278 }
279 }
280 })
281 }
282}
283
284impl BacktraceResolver {
285 #[allow(clippy::return_self_not_must_use)]
289 pub fn resolve(mut self) -> Self {
290 if self.resolved {
291 return self;
292 }
293
294 for frm in &self.bt.frames {
295 if let Some(frm) = frm {
296 let ip = frm.ip();
297 if self.frames.contains_key(&ip) {
298 continue;
299 }
300 self.frames
301 .insert(ip, Arc::new(ResolvedFrame::resolve(frm)));
302 }
303 }
304
305 let mut idx = 0;
306 let mut frames: [Option<&ResolvedFrame>; 80] = [None; 80];
307 for frm in &self.bt.frames {
308 if let Some(frm) = frm {
309 let ip = frm.ip();
310 frames[idx] = Some(self.frames[&ip].as_ref());
311 idx += 1;
312 }
313 }
314
315 find_loc(self.bt.location, &mut frames);
316
317 #[allow(static_mut_refs)]
318 {
319 if let Some(start) = unsafe { START } {
320 find_loc_start(start, &mut frames);
321 }
322 if let Some(start) = unsafe { START_ALT } {
323 find_loc_start(start, &mut frames);
324 }
325 PATHS2.with(|paths| {
326 for s in paths {
327 find_loc_start((s.as_str(), 0), &mut frames);
328 }
329 });
330 }
331
332 let mut idx = 0;
333 for frm in &mut frames {
334 if frm.is_some() {
335 if idx > 10 {
336 *frm = None;
337 } else {
338 idx += 1;
339 }
340 }
341 }
342
343 let bt = Bt(&frames[..]);
344 let mut buf = String::new();
345 let _ = write!(&mut buf, "\n{bt:?}");
346 self.repr = Some(Arc::from(buf));
347
348 self
349 }
350}
351
352impl Drop for BacktraceResolver {
353 fn drop(&mut self) {
354 if !self.resolved {
355 if let Some(repr) = self.repr.take() {
356 REPRS.with(|r| {
357 r.borrow_mut().insert(self.bt.id, repr);
358 });
359 }
360
361 FRAMES.with(|c| {
362 let mut cache = c.borrow_mut();
363
364 for (ip, frm) in &self.frames {
365 let ip = frm.ip;
366 if !cache.contains_key(&ip) {
367 cache.insert(ip, frm.clone());
368 }
369 }
370 });
371 }
372 }
373}
374
375fn find_loc(loc: &str, frames: &mut [Option<&ResolvedFrame>]) {
376 let mut idx = 0;
377
378 'outter: for (i, frm) in frames.iter().enumerate() {
379 if let Some(f) = frm {
380 for sym in &f.symbols {
381 if let Some(fname) = &sym.filename
382 && fname.ends_with(loc)
383 {
384 idx = i;
385 break 'outter;
386 }
387 }
388 } else {
389 break;
390 }
391 }
392
393 for f in frames.iter_mut().take(idx) {
394 *f = None;
395 }
396
397 PATHS.with(|paths| {
398 'outter: for frm in &mut frames[idx..] {
399 if let Some(f) = frm {
400 for sym in &f.symbols {
401 if let Some(fname) = &sym.filename {
402 for p in paths {
403 if fname.ends_with(p) {
404 *frm = None;
405 continue 'outter;
406 }
407 }
408 }
409 }
410 }
411 }
412 });
413}
414
415thread_local! {
416 static PATHS: Vec<String> = {
417 let mut paths = Vec::new();
418 for item in [
419 &["src", "ctx.rs"][..],
420 &["src", "map_err.rs"][..],
421 &["src", "and_then.rs"][..],
422 &["src", "fn_service.rs"][..],
423 &["src", "pipeline.rs"][..],
424 &["src", "net", "factory.rs"][..],
425 &["src", "future", "future.rs"][..],
426 &["src", "net", "service.rs"][..],
427 &["src", "boxed.rs"][..],
428 &["src", "error.rs"][..],
429 &["src", "wrk.rs"][..],
430 &["src", "future.rs"][..],
431 &["std", "src", "thread", "local.rs"][..],
432 ] {
433 paths.push(item.iter().collect::<path::PathBuf>().to_string_lossy().into_owned());
434 }
435 paths
436 };
437
438 static PATHS2: Vec<String> = {
439 let mut paths = Vec::new();
440 for item in [
441 &["src", "driver.rs"][..],
442 &["src", "rt_compio.rs"][..],
443 &["core", "src", "panic", "unwind_safe.rs"][..],
444 &["src", "runtime", "task", "core.rs"][..]
445 ] {
446 paths.push(item.iter().collect::<path::PathBuf>().to_string_lossy().into_owned());
447 }
448 paths
449 }
450}
451
452fn find_loc_start(loc: (&str, u32), frames: &mut [Option<&ResolvedFrame>]) {
453 let mut idx = 0;
454 while idx < frames.len() {
455 if let Some(frm) = &frames[idx] {
456 for sym in &frm.symbols {
457 if let Some(fname) = &sym.filename
458 && let Some(lineno) = sym.lineno
459 && fname.ends_with(loc.0)
460 && (loc.1 == 0 || lineno == loc.1)
461 {
462 for f in frames.iter_mut().skip(idx) {
463 if f.is_some() {
464 *f = None;
465 }
466 }
467 return;
468 }
469 }
470 }
471 idx += 1;
472 }
473}
474
475struct Bt<'a>(&'a [Option<&'a ResolvedFrame>]);
476
477impl fmt::Debug for Bt<'_> {
478 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
479 let cwd = std::env::current_dir();
480 let mut print_path = move |fmt: &mut fmt::Formatter<'_>, path: BytesOrWideString<'_>| {
481 let path = crate::utils::module_path_fs(path.to_str_lossy().as_ref());
482 fmt::Display::fmt(&path, fmt)
483 };
484
485 let mut f = BacktraceFmt::new(fmt, backtrace::PrintFmt::Short, &mut print_path);
486 f.add_context()?;
487 for frm in self.0.iter().flatten() {
488 let ip = frm.ip as *mut c_void;
489 let mut ff = f.frame();
490 for sym in &frm.symbols {
491 ff.print_raw_with_column(
492 ip,
493 sym.name.as_deref().map(SymbolName::new),
494 sym.filename
495 .as_deref()
496 .and_then(|p| Some(BytesOrWideString::Bytes(p.to_str()?.as_bytes()))),
497 sym.lineno,
498 sym.colno,
499 )?;
500 }
501 if frm.symbols.is_empty() {
502 ff.print_raw(ip, None, None, None)?;
503 }
504 }
505 f.finish()?;
506 Ok(())
507 }
508}
509
510impl fmt::Debug for Backtrace {
511 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
512 if let Some(repr) = self.repr() {
513 fmt::Display::fmt(repr.as_ref(), f)
514 } else {
515 Ok(())
516 }
517 }
518}
519
520impl fmt::Display for Backtrace {
521 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
522 if let Some(repr) = self.repr() {
523 fmt::Display::fmt(repr.as_ref(), f)
524 } else {
525 Ok(())
526 }
527 }
528}