1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
/* 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 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(())
}
}
// Several types in this file are currently not used in a Linux or Windows build.
#[allow(dead_code)]
pub type Address = *const u8;
/// 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 += 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
}
}
|