servo/components/background_hang_monitor/sampler.rs
2019-06-22 14:59:09 +02:00

99 lines
2.8 KiB
Rust

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use backtrace;
use msg::constellation_msg::{HangProfile, HangProfileSymbol};
use std::ptr;
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() -> Box<dyn Sampler> {
Box::new(DummySampler)
}
}
impl Sampler for DummySampler {
fn suspend_and_sample_thread(&self) -> Result<NativeStack, ()> {
Err(())
}
}
// Several types in this file are currently not used in a Linux or Windows build.
#[allow(dead_code)]
pub type Address = *const libc::uint8_t;
/// The registers used for stack unwinding
#[allow(dead_code)]
pub struct Registers {
/// Instruction pointer.
pub instruction_ptr: Address,
/// Stack pointer.
pub stack_ptr: Address,
/// Frame pointer.
pub frame_ptr: Address,
}
pub struct NativeStack {
instruction_ptrs: [*mut std::ffi::c_void; MAX_NATIVE_FRAMES],
stack_ptrs: [*mut std::ffi::c_void; MAX_NATIVE_FRAMES],
count: usize,
}
impl NativeStack {
pub fn new() -> Self {
NativeStack {
instruction_ptrs: [ptr::null_mut(); MAX_NATIVE_FRAMES],
stack_ptrs: [ptr::null_mut(); MAX_NATIVE_FRAMES],
count: 0,
}
}
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 = 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| {
// TODO: use the demangled or C++ demangled symbols if available.
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
}
}