background_hang_monitor/
sampler.rs1use std::ptr;
6
7use background_hang_monitor_api::{HangProfile, HangProfileSymbol};
8
9const MAX_NATIVE_FRAMES: usize = 1024;
10
11pub trait Sampler: Send {
12 fn suspend_and_sample_thread(&self) -> Result<NativeStack, ()>;
13}
14
15#[allow(dead_code)]
16pub struct DummySampler;
17
18impl DummySampler {
19 #[allow(dead_code)]
20 pub fn new_boxed() -> Box<dyn Sampler> {
21 Box::new(DummySampler)
22 }
23}
24
25impl Sampler for DummySampler {
26 fn suspend_and_sample_thread(&self) -> Result<NativeStack, ()> {
27 Err(())
28 }
29}
30
31#[allow(dead_code)]
33pub type Address = *const u8;
34
35#[allow(dead_code)]
37pub struct Registers {
38 pub instruction_ptr: Address,
40 pub stack_ptr: Address,
42 pub frame_ptr: Address,
44}
45
46#[allow(dead_code)]
47pub struct NativeStack {
48 instruction_ptrs: [*mut std::ffi::c_void; MAX_NATIVE_FRAMES],
49 #[allow(dead_code)]
50 stack_ptrs: [*mut std::ffi::c_void; MAX_NATIVE_FRAMES],
51 #[allow(dead_code)]
52 count: usize,
53}
54
55impl NativeStack {
56 #[allow(dead_code)]
57 pub fn new() -> Self {
58 NativeStack {
59 instruction_ptrs: [ptr::null_mut(); MAX_NATIVE_FRAMES],
60 stack_ptrs: [ptr::null_mut(); MAX_NATIVE_FRAMES],
61 count: 0,
62 }
63 }
64
65 #[allow(dead_code)]
66 pub fn process_register(
67 &mut self,
68 instruction_ptr: *mut std::ffi::c_void,
69 stack_ptr: *mut std::ffi::c_void,
70 ) -> Result<(), ()> {
71 if self.count >= MAX_NATIVE_FRAMES {
72 return Err(());
73 }
74 self.instruction_ptrs[self.count] = instruction_ptr;
75 self.stack_ptrs[self.count] = stack_ptr;
76 self.count += 1;
77 Ok(())
78 }
79
80 pub fn to_hangprofile(&self) -> HangProfile {
81 let mut profile = HangProfile {
82 backtrace: Vec::new(),
83 };
84 for ip in self.instruction_ptrs.iter().rev() {
85 if ip.is_null() {
86 continue;
87 }
88 backtrace::resolve(*ip, |symbol| {
89 let name = symbol
90 .name()
91 .map(|n| String::from_utf8_lossy(n.as_bytes()).to_string());
92 #[cfg(feature = "sampler")]
96 let name = name.map(|n| rustc_demangle::demangle(&n).to_string());
97
98 let filename = symbol.filename().map(|n| n.to_string_lossy().to_string());
99 let lineno = symbol.lineno();
100 profile.backtrace.push(HangProfileSymbol {
101 name,
102 filename,
103 lineno,
104 });
105 });
106 }
107 profile
108 }
109}