-
Notifications
You must be signed in to change notification settings - Fork 1.4k
/
Copy pathsystemv.rs
90 lines (79 loc) · 3.16 KB
/
systemv.rs
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
//! Module for System V ABI unwind registry.
use anyhow::Result;
/// Represents a registration of function unwind information for System V ABI.
pub struct UnwindRegistration {
registrations: Vec<usize>,
}
extern "C" {
// libunwind import
fn __register_frame(fde: *const u8);
fn __deregister_frame(fde: *const u8);
}
impl UnwindRegistration {
pub const SECTION_NAME: &str = ".eh_frame";
/// Registers precompiled unwinding information with the system.
///
/// The `_base_address` field is ignored here (only used on other
/// platforms), but the `unwind_info` and `unwind_len` parameters should
/// describe an in-memory representation of a `.eh_frame` section. This is
/// typically arranged for by the `wasmtime-obj` crate.
pub unsafe fn new(
_base_address: *const u8,
unwind_info: *const u8,
unwind_len: usize,
) -> Result<UnwindRegistration> {
debug_assert_eq!(
unwind_info as usize % wasmtime_runtime::page_size(),
0,
"The unwind info must always be aligned to a page"
);
let mut registrations = Vec::new();
if cfg!(any(
all(target_os = "linux", target_env = "gnu"),
target_os = "freebsd"
)) {
// On gnu (libgcc), `__register_frame` will walk the FDEs until an
// entry of length 0
__register_frame(unwind_info);
registrations.push(unwind_info as usize);
} else {
// For libunwind, `__register_frame` takes a pointer to a single
// FDE. Note that we subtract 4 from the length of unwind info since
// wasmtime-encode .eh_frame sections always have a trailing 32-bit
// zero for the platforms above.
let start = unwind_info;
let end = start.add(unwind_len - 4);
let mut current = start;
// Walk all of the entries in the frame table and register them
while current < end {
let len = std::ptr::read::<u32>(current as *const u32) as usize;
// Skip over the CIE
if current != start {
__register_frame(current);
registrations.push(current as usize);
}
// Move to the next table entry (+4 because the length itself is
// not inclusive)
current = current.add(len + 4);
}
}
Ok(UnwindRegistration { registrations })
}
}
impl Drop for UnwindRegistration {
fn drop(&mut self) {
unsafe {
// libgcc stores the frame entries as a linked list in decreasing
// sort order based on the PC value of the registered entry.
//
// As we store the registrations in increasing order, it would be
// O(N^2) to deregister in that order.
//
// To ensure that we just pop off the first element in the list upon
// every deregistration, walk our list of registrations backwards.
for fde in self.registrations.iter().rev() {
__deregister_frame(*fde as *const _);
}
}
}
}