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");
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) {
20 unsafe {
21 START = Some((file, line));
22 }
23}
24
25#[doc(hidden)]
26pub fn set_backtrace_start_alt(file: &'static str, line: u32) {
27 unsafe {
28 START_ALT = Some((file, line));
29 }
30}
31
32#[derive(Clone)]
33pub struct Backtrace(Arc<BacktraceInner>);
39
40#[derive(Debug)]
41pub struct BacktraceResolver {
50 bt: Arc<BacktraceInner>,
51 repr: Option<Arc<str>>,
52 resolved: bool,
53 frames: HashMap<usize, Arc<BacktraceFrame>>,
54}
55
56#[derive(Debug)]
57struct BacktraceInner {
58 id: u64,
59 frames: [Option<Frame>; 80],
60 location: &'static Location<'static>,
61}
62
63impl Backtrace {
64 pub fn new(location: &'static Location<'static>) -> Self {
66 let mut st = foldhash::fast::FixedState::default().build_hasher();
67 let mut idx = 0;
68 let mut frames: [Option<Frame>; 80] = [const { None }; 80];
69
70 backtrace::trace(|frm| {
71 let ip = frm.ip();
72 st.write_usize(ip as usize);
73 frames[idx] = Some(frm.clone());
74 idx += 1;
75 idx < 80
76 });
77 let id = st.finish();
78
79 Self(Arc::new(BacktraceInner {
80 id,
81 frames,
82 location,
83 }))
84 }
85
86 pub fn repr(&self) -> Option<Arc<str>> {
88 REPRS.with(|r| r.borrow_mut().get(&self.0.id).cloned())
89 }
90
91 pub fn is_resolved(&self) -> bool {
92 REPRS.with(|r| r.borrow_mut().contains_key(&self.0.id))
93 }
94
95 pub fn resolver(&self) -> BacktraceResolver {
96 REPRS.with(|r| {
97 let mut reprs = r.borrow_mut();
98 if let Some(repr) = reprs.get(&self.0.id) {
99 BacktraceResolver {
100 repr: None,
101 resolved: true,
102 bt: self.0.clone(),
103 frames: HashMap::default(),
104 }
105 } else {
106 DEFAULT.with(|s| {
107 reprs.insert(self.0.id, s.clone());
108 });
109
110 let mut frames = HashMap::default();
111
112 FRAMES.with(|c| {
113 let mut cache = c.borrow();
114
115 for frm in &self.0.frames {
116 if let Some(frm) = frm {
117 let ip = frm.ip() as usize;
118 if let Some(frame) = cache.get(&ip) {
119 frames.insert(ip, frame.clone());
120 }
121 }
122 }
123 });
124
125 BacktraceResolver {
126 frames,
127 resolved: false,
128 repr: None,
129 bt: self.0.clone(),
130 }
131 }
132 })
133 }
134}
135
136impl BacktraceResolver {
137 #[allow(clippy::return_self_not_must_use)]
138 pub fn resolve(mut self) -> Self {
139 if self.resolved {
140 return self;
141 }
142
143 for frm in &self.bt.frames {
144 if let Some(frm) = frm {
145 let ip = frm.ip() as usize;
146 if self.frames.contains_key(&ip) {
147 continue;
148 }
149
150 let mut f = BacktraceFrame::from(frm.clone());
151 f.resolve();
152 self.frames.insert(ip, Arc::new(f));
153 }
154 }
155
156 let mut idx = 0;
157 let mut frames: [Option<&BacktraceFrame>; 80] = [None; 80];
158 for frm in &self.bt.frames {
159 if let Some(frm) = frm {
160 let ip = frm.ip() as usize;
161 frames[idx] = Some(self.frames[&ip].as_ref());
162 idx += 1;
163 }
164 }
165
166 find_loc(self.bt.location, &mut frames);
167
168 #[allow(static_mut_refs)]
169 {
170 if let Some(start) = unsafe { START } {
171 find_loc_start(start, &mut frames);
172 }
173 if let Some(start) = unsafe { START_ALT } {
174 find_loc_start(start, &mut frames);
175 }
176 PATHS2.with(|paths| {
177 for s in paths {
178 find_loc_start((s.as_str(), 0), &mut frames);
179 }
180 });
181 }
182
183 let mut idx = 0;
184 for frm in &mut frames {
185 if frm.is_some() {
186 if idx > 10 {
187 *frm = None;
188 } else {
189 idx += 1;
190 }
191 }
192 }
193
194 let bt = Bt(&frames[..]);
195 let mut buf = String::new();
196 let _ = write!(&mut buf, "\n{bt:?}");
197 self.repr = Some(Arc::from(buf));
198
199 self
200 }
201}
202
203impl Drop for BacktraceResolver {
204 fn drop(&mut self) {
205 if !self.resolved {
206 if let Some(repr) = self.repr.take() {
207 REPRS.with(|r| {
208 r.borrow_mut().insert(self.bt.id, repr);
209 });
210 }
211
212 FRAMES.with(|c| {
213 let mut cache = c.borrow_mut();
214
215 for (ip, frm) in &self.frames {
216 let ip = frm.ip() as usize;
217 if !cache.contains_key(&ip) {
218 cache.insert(ip, frm.clone());
219 }
220 }
221 });
222 }
223 }
224}
225
226fn find_loc(loc: &Location<'_>, frames: &mut [Option<&BacktraceFrame>]) {
227 let mut idx = 0;
228
229 'outter: for (i, frm) in frames.iter().enumerate() {
230 if let Some(f) = frm {
231 for sym in f.symbols() {
232 if let Some(fname) = sym.filename()
233 && fname.ends_with(loc.file())
234 {
235 idx = i;
236 break 'outter;
237 }
238 }
239 } else {
240 break;
241 }
242 }
243
244 for f in frames.iter_mut().take(idx) {
245 *f = None;
246 }
247
248 PATHS.with(|paths| {
249 'outter: for frm in &mut frames[idx..] {
250 if let Some(f) = frm {
251 for sym in f.symbols() {
252 if let Some(fname) = sym.filename() {
253 for p in paths {
254 if fname.ends_with(p) {
255 *frm = None;
256 continue 'outter;
257 }
258 }
259 }
260 }
261 }
262 }
263 });
264}
265
266thread_local! {
267 static PATHS: Vec<String> = {
268 let mut paths = Vec::new();
269 for item in [
270 &["src", "ctx.rs"][..],
271 &["src", "map_err.rs"][..],
272 &["src", "and_then.rs"][..],
273 &["src", "fn_service.rs"][..],
274 &["src", "pipeline.rs"][..],
275 &["src", "net", "factory.rs"][..],
276 &["src", "future", "future.rs"][..],
277 &["src", "net", "service.rs"][..],
278 &["src", "boxed.rs"][..],
279 &["src", "error.rs"][..],
280 &["src", "wrk.rs"][..],
281 &["src", "future.rs"][..],
282 &["std", "src", "thread", "local.rs"][..],
283 ] {
284 paths.push(item.iter().collect::<path::PathBuf>().to_string_lossy().into_owned());
285 }
286 paths
287 };
288
289 static PATHS2: Vec<String> = {
290 let mut paths = Vec::new();
291 for item in [
292 &["src", "driver.rs"][..],
293 &["src", "rt_compio.rs"][..],
294 &["core", "src", "panic", "unwind_safe.rs"][..],
295 &["src", "runtime", "task", "core.rs"][..]
296 ] {
297 paths.push(item.iter().collect::<path::PathBuf>().to_string_lossy().into_owned());
298 }
299 paths
300 }
301}
302
303fn find_loc_start(loc: (&str, u32), frames: &mut [Option<&BacktraceFrame>]) {
304 let mut idx = 0;
305 while idx < frames.len() {
306 if let Some(frm) = &frames[idx] {
307 for sym in frm.symbols() {
308 if let Some(fname) = sym.filename()
309 && let Some(lineno) = sym.lineno()
310 && fname.ends_with(loc.0)
311 && (loc.1 == 0 || lineno == loc.1)
312 {
313 for f in frames.iter_mut().skip(idx) {
314 if f.is_some() {
315 *f = None;
316 }
317 }
318 return;
319 }
320 }
321 }
322 idx += 1;
323 }
324}
325
326struct Bt<'a>(&'a [Option<&'a BacktraceFrame>]);
327
328impl fmt::Debug for Bt<'_> {
329 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
330 let cwd = std::env::current_dir();
331 let mut print_path =
332 move |fmt: &mut fmt::Formatter<'_>, path: BytesOrWideString<'_>| {
333 let path = path.into_path_buf();
334 if let Ok(cwd) = &cwd
335 && let Ok(suffix) = path.strip_prefix(cwd)
336 {
337 return fmt::Display::fmt(&suffix.display(), fmt);
338 }
339 fmt::Display::fmt(&path.display(), fmt)
340 };
341
342 let mut f = BacktraceFmt::new(fmt, backtrace::PrintFmt::Short, &mut print_path);
343 f.add_context()?;
344 for frm in self.0.iter().flatten() {
345 f.frame().backtrace_frame(frm)?;
346 }
347 f.finish()?;
348 Ok(())
349 }
350}
351
352impl fmt::Debug for Backtrace {
353 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
354 if let Some(repr) = self.repr() {
355 fmt::Display::fmt(repr.as_ref(), f)
356 } else {
357 Ok(())
358 }
359 }
360}
361
362impl fmt::Display for Backtrace {
363 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
364 if let Some(repr) = self.repr() {
365 fmt::Display::fmt(repr.as_ref(), f)
366 } else {
367 Ok(())
368 }
369 }
370}