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