use std::ptr;
use background_hang_monitor_api::{HangProfile, HangProfileSymbol};
const MAX_NATIVE_FRAMES: usize = 1024;
pub trait Sampler: Send {
fn suspend_and_sample_thread(&self) -> Result<NativeStack, ()>;
}
#[allow(dead_code)]
pub struct DummySampler;
impl DummySampler {
#[allow(dead_code)]
pub fn new_boxed() -> Box<dyn Sampler> {
Box::new(DummySampler)
}
}
impl Sampler for DummySampler {
fn suspend_and_sample_thread(&self) -> Result<NativeStack, ()> {
Err(())
}
}
#[allow(dead_code)]
pub type Address = *const u8;
#[allow(dead_code)]
pub struct Registers {
pub instruction_ptr: Address,
pub stack_ptr: Address,
pub frame_ptr: Address,
}
#[allow(dead_code)]
pub struct NativeStack {
instruction_ptrs: [*mut std::ffi::c_void; MAX_NATIVE_FRAMES],
#[allow(dead_code)]
stack_ptrs: [*mut std::ffi::c_void; MAX_NATIVE_FRAMES],
#[allow(dead_code)]
count: usize,
}
impl NativeStack {
#[allow(dead_code)]
pub fn new() -> Self {
NativeStack {
instruction_ptrs: [ptr::null_mut(); MAX_NATIVE_FRAMES],
stack_ptrs: [ptr::null_mut(); MAX_NATIVE_FRAMES],
count: 0,
}
}
#[allow(dead_code)]
pub fn process_register(
&mut self,
instruction_ptr: *mut std::ffi::c_void,
stack_ptr: *mut std::ffi::c_void,
) -> Result<(), ()> {
if self.count >= MAX_NATIVE_FRAMES {
return Err(());
}
self.instruction_ptrs[self.count] = instruction_ptr;
self.stack_ptrs[self.count] = stack_ptr;
self.count += 1;
Ok(())
}
pub fn to_hangprofile(&self) -> HangProfile {
let mut profile = HangProfile {
backtrace: Vec::new(),
};
for ip in self.instruction_ptrs.iter().rev() {
if ip.is_null() {
continue;
}
backtrace::resolve(*ip, |symbol| {
let name = symbol
.name()
.map(|n| String::from_utf8_lossy(n.as_bytes()).to_string());
let filename = symbol.filename().map(|n| n.to_string_lossy().to_string());
let lineno = symbol.lineno();
profile.backtrace.push(HangProfileSymbol {
name,
filename,
lineno,
});
});
}
profile
}
}