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