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};
7
8use backtrace::{BacktraceFmt, BacktraceFrame, BytesOrWideString, Frame};
9
10thread_local! {
11 static FRAMES: RefCell<HashMap<*mut os::raw::c_void, BacktraceFrame>> = RefCell::new(HashMap::default());
12 static REPRS: RefCell<HashMap<u64, Arc<str>>> = RefCell::new(HashMap::default());
13}
14static mut START: Option<(&'static str, u32)> = None;
15static mut START_ALT: Option<(&'static str, u32)> = None;
16
17pub fn set_backtrace_start(file: &'static str, line: u32) {
18 unsafe {
19 START = Some((file, line));
20 }
21}
22
23#[doc(hidden)]
24pub fn set_backtrace_start_alt(file: &'static str, line: u32) {
25 unsafe {
26 START_ALT = Some((file, line));
27 }
28}
29
30#[derive(Clone)]
31pub struct Backtrace(Arc<BacktraceInner>);
37
38struct BacktraceInner {
39 id: u64,
40 frames: [Option<Frame>; 80],
41 location: &'static Location<'static>,
42}
43
44impl Backtrace {
45 pub fn new(location: &'static Location<'static>) -> Self {
47 let mut st = foldhash::fast::FixedState::default().build_hasher();
48 let mut idx = 0;
49 let mut frames: [Option<Frame>; 80] = [const { None }; 80];
50
51 backtrace::trace(|frm| {
52 let ip = frm.ip();
53 st.write_usize(ip as usize);
54 frames[idx] = Some(frm.clone());
55 idx += 1;
56 idx < 80
57 });
58 let id = st.finish();
59
60 Self(Arc::new(BacktraceInner {
61 id,
62 frames,
63 location,
64 }))
65 }
66
67 pub fn repr(&self) -> Option<Arc<str>> {
69 REPRS.with(|r| r.borrow_mut().get(&self.0.id).cloned())
70 }
71
72 pub fn is_resolved(&self) -> bool {
73 REPRS.with(|r| r.borrow_mut().contains_key(&self.0.id))
74 }
75
76 pub fn resolve(&self) {
77 REPRS.with(|r| {
78 let mut reprs = r.borrow_mut();
79 if reprs.contains_key(&self.0.id) {
80 return;
81 }
82
83 FRAMES.with(|c| {
84 let mut cache = c.borrow_mut();
85
86 for frm in &self.0.frames {
87 if let Some(frm) = frm {
88 let ip = frm.ip();
89 cache.entry(ip).or_insert_with(|| {
90 let mut f = BacktraceFrame::from(frm.clone());
91 f.resolve();
92 f
93 });
94 }
95 }
96
97 let mut idx = 0;
98 let mut frames: [Option<&BacktraceFrame>; 80] = [None; 80];
99 for frm in &self.0.frames {
100 if let Some(frm) = frm {
101 frames[idx] = Some(&cache[&frm.ip()]);
102 idx += 1;
103 }
104 }
105
106 find_loc(self.0.location, &mut frames);
107
108 #[allow(static_mut_refs)]
109 {
110 if let Some(start) = unsafe { START } {
111 find_loc_start(start, &mut frames);
112 }
113 if let Some(start) = unsafe { START_ALT } {
114 find_loc_start(start, &mut frames);
115 }
116 PATHS2.with(|paths| {
117 for s in paths {
118 find_loc_start((s.as_str(), 0), &mut frames);
119 }
120 });
121 }
122
123 let mut idx = 0;
124 for frm in &mut frames {
125 if frm.is_some() {
126 if idx > 10 {
127 *frm = None;
128 } else {
129 idx += 1;
130 }
131 }
132 }
133
134 let bt = Bt(&frames[..]);
135 let mut buf = String::new();
136 let _ = write!(&mut buf, "\n{bt:?}");
137 let repr: Arc<str> = Arc::from(buf);
138 reprs.insert(self.0.id, repr.clone());
139 repr
140 });
141 });
142 }
143}
144
145fn find_loc(loc: &Location<'_>, frames: &mut [Option<&BacktraceFrame>]) {
146 let mut idx = 0;
147
148 'outter: for (i, frm) in frames.iter().enumerate() {
149 if let Some(f) = frm {
150 for sym in f.symbols() {
151 if let Some(fname) = sym.filename()
152 && fname.ends_with(loc.file())
153 {
154 idx = i;
155 break 'outter;
156 }
157 }
158 } else {
159 break;
160 }
161 }
162
163 for f in frames.iter_mut().take(idx) {
164 *f = None;
165 }
166
167 PATHS.with(|paths| {
168 'outter: for frm in &mut frames[idx..] {
169 if let Some(f) = frm {
170 for sym in f.symbols() {
171 if let Some(fname) = sym.filename() {
172 for p in paths {
173 if fname.ends_with(p) {
174 *frm = None;
175 continue 'outter;
176 }
177 }
178 }
179 }
180 }
181 }
182 });
183}
184
185thread_local! {
186 static PATHS: Vec<String> = {
187 let mut paths = Vec::new();
188 for item in [
189 &["src", "ctx.rs"][..],
190 &["src", "map_err.rs"][..],
191 &["src", "and_then.rs"][..],
192 &["src", "fn_service.rs"][..],
193 &["src", "pipeline.rs"][..],
194 &["src", "net", "factory.rs"][..],
195 &["src", "future", "future.rs"][..],
196 &["src", "net", "service.rs"][..],
197 &["src", "boxed.rs"][..],
198 &["src", "error.rs"][..],
199 &["src", "wrk.rs"][..],
200 &["src", "future.rs"][..],
201 &["std", "src", "thread", "local.rs"][..],
202 ] {
203 paths.push(item.iter().collect::<path::PathBuf>().to_string_lossy().into_owned());
204 }
205 paths
206 };
207
208 static PATHS2: Vec<String> = {
209 let mut paths = Vec::new();
210 for item in [
211 &["src", "driver.rs"][..],
212 &["src", "rt_compio.rs"][..],
213 &["core", "src", "panic", "unwind_safe.rs"][..],
214 &["src", "runtime", "task", "core.rs"][..]
215 ] {
216 paths.push(item.iter().collect::<path::PathBuf>().to_string_lossy().into_owned());
217 }
218 paths
219 }
220}
221
222fn find_loc_start(loc: (&str, u32), frames: &mut [Option<&BacktraceFrame>]) {
223 let mut idx = 0;
224 while idx < frames.len() {
225 if let Some(frm) = &frames[idx] {
226 for sym in frm.symbols() {
227 if let Some(fname) = sym.filename()
228 && let Some(lineno) = sym.lineno()
229 && fname.ends_with(loc.0)
230 && (loc.1 == 0 || lineno == loc.1)
231 {
232 for f in frames.iter_mut().skip(idx) {
233 if f.is_some() {
234 *f = None;
235 }
236 }
237 return;
238 }
239 }
240 }
241 idx += 1;
242 }
243}
244
245struct Bt<'a>(&'a [Option<&'a BacktraceFrame>]);
246
247impl fmt::Debug for Bt<'_> {
248 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
249 let cwd = std::env::current_dir();
250 let mut print_path =
251 move |fmt: &mut fmt::Formatter<'_>, path: BytesOrWideString<'_>| {
252 let path = path.into_path_buf();
253 if let Ok(cwd) = &cwd
254 && let Ok(suffix) = path.strip_prefix(cwd)
255 {
256 return fmt::Display::fmt(&suffix.display(), fmt);
257 }
258 fmt::Display::fmt(&path.display(), fmt)
259 };
260
261 let mut f = BacktraceFmt::new(fmt, backtrace::PrintFmt::Short, &mut print_path);
262 f.add_context()?;
263 for frm in self.0.iter().flatten() {
264 f.frame().backtrace_frame(frm)?;
265 }
266 f.finish()?;
267 Ok(())
268 }
269}
270
271impl fmt::Debug for Backtrace {
272 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
273 if let Some(repr) = self.repr() {
274 fmt::Display::fmt(repr.as_ref(), f)
275 } else {
276 Ok(())
277 }
278 }
279}
280
281impl fmt::Display for Backtrace {
282 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
283 if let Some(repr) = self.repr() {
284 fmt::Display::fmt(repr.as_ref(), f)
285 } else {
286 Ok(())
287 }
288 }
289}