1#[cfg(not(all(
2 feature = "frame-pointer",
3 target_os = "linux",
4 any(target_arch = "x86_64", target_arch = "aarch64")
5)))]
6use backtrace::trace;
7#[cfg(all(
8 feature = "frame-pointer",
9 target_os = "linux",
10 any(target_arch = "x86_64", target_arch = "aarch64")
11))]
12use frame_pointer::trace;
13
14use itertools::Itertools;
15use serde::Serialize;
16use smallvec::SmallVec;
17use std::fmt;
18use std::hash::{Hash, Hasher};
19
20#[cfg(not(all(
21 feature = "frame-pointer",
22 target_os = "linux",
23 any(target_arch = "x86_64", target_arch = "aarch64")
24)))]
25mod backtrace;
26#[cfg(all(
27 feature = "frame-pointer",
28 target_os = "linux",
29 any(target_arch = "x86_64", target_arch = "aarch64")
30))]
31mod frame_pointer;
32
33const SOFT_MAX_DEPTH: usize = 128;
34
35#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
36pub enum CaptureMode {
37 FramePointer,
38 Backtrace,
39}
40
41#[cfg(all(
42 feature = "frame-pointer",
43 target_os = "linux",
44 any(target_arch = "x86_64", target_arch = "aarch64")
45))]
46pub const fn capture_mode() -> CaptureMode {
47 CaptureMode::FramePointer
48}
49
50#[cfg(not(all(
51 feature = "frame-pointer",
52 target_os = "linux",
53 any(target_arch = "x86_64", target_arch = "aarch64")
54)))]
55pub const fn capture_mode() -> CaptureMode {
56 CaptureMode::Backtrace
57}
58
59#[derive(Clone)]
60struct UnresolvedFrames(SmallVec<[u64; SOFT_MAX_DEPTH]>);
61
62impl From<SmallVec<[u64; SOFT_MAX_DEPTH]>> for UnresolvedFrames {
63 fn from(x: SmallVec<[u64; SOFT_MAX_DEPTH]>) -> Self {
64 Self(x)
65 }
66}
67
68#[derive(Clone)]
69pub struct HashedBacktrace {
70 inner: UnresolvedFrames,
71 hash: u64,
72}
73
74impl fmt::Debug for HashedBacktrace {
75 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76 let address = self.inner.0.iter().map(|x| format!("{:#x}", x)).join(" ");
77 f.write_str(&address)
78 }
79}
80
81impl HashedBacktrace {
82 pub fn capture() -> Self {
83 let bt = trace();
84 let mut hasher = ahash::AHasher::default();
85 bt.0.iter().for_each(|x| hasher.write_u64(*x));
86 let hash = hasher.finish();
87 Self { inner: bt, hash }
88 }
89 pub fn addrs(&self) -> Vec<u64> {
90 self.inner.0.iter().copied().collect_vec()
91 }
92}
93
94impl PartialEq for HashedBacktrace {
95 fn eq(&self, other: &Self) -> bool {
96 self.hash == other.hash && self.inner.0 == other.inner.0
97 }
98}
99
100impl Eq for HashedBacktrace {}
101
102impl Hash for HashedBacktrace {
103 fn hash<H: Hasher>(&self, state: &mut H) {
104 self.inner.0.iter().for_each(|x| state.write_u64(*x));
105 }
106}