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