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