Skip to content

Commit

Permalink
Register individual FDEs for musl libc.
Browse files Browse the repository at this point in the history
When targeting musl, libunwind is used for the `__register_frame`
implementation.

Unlike when targeting libgcc which expects an entire frame table, the libunwind
implementation expects a single FDE.

This change ensures Wasmtime registers each individual FDE when targeting musl.

Fixes #1904.
  • Loading branch information
peterhuene committed Jun 24, 2020
1 parent 9751b96 commit 7536093
Showing 1 changed file with 27 additions and 26 deletions.
53 changes: 27 additions & 26 deletions crates/jit/src/unwind/systemv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,40 +90,41 @@ impl UnwindRegistry {
let mut eh_frame = EhFrame(EndianVec::new(RunTimeEndian::default()));
table.write_eh_frame(&mut eh_frame).unwrap();

// GCC expects a terminating "empty" length, so write a 0 length at the end of the table.
eh_frame.0.write_u32(0).unwrap();
if cfg!(all(target_os = "linux", any(target_env = "gnu", target_env = ""))) {
// libgcc expects a terminating "empty" length, so write a 0 length at the end of the table.
eh_frame.0.write_u32(0).unwrap();

}

self.frame_table = eh_frame.0.into_vec();

Ok(())
}

unsafe fn register_frames(&mut self) {
cfg_if::cfg_if! {
if #[cfg(target_os = "macos")] {
// On macOS, `__register_frame` takes a pointer to a single FDE
let start = self.frame_table.as_ptr();
let end = start.add(self.frame_table.len());
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);
self.registrations.push(current as usize);
}

// Move to the next table entry (+4 because the length itself is not inclusive)
current = current.add(len + 4);
if cfg!(all(target_os = "linux", any(target_env = "gnu", target_env = ""))) {
// On gnu (libgcc), `__register_frame` will walk the FDEs until an entry of length 0
let ptr = self.frame_table.as_ptr();
__register_frame(ptr);
self.registrations.push(ptr as usize);
} else {
// For libunwind, `__register_frame` takes a pointer to a single FDE
let start = self.frame_table.as_ptr();
let end = start.add(self.frame_table.len());
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);
self.registrations.push(current as usize);
}
} else {
// On other platforms, `__register_frame` will walk the FDEs until an entry of length 0
let ptr = self.frame_table.as_ptr();
__register_frame(ptr);
self.registrations.push(ptr as usize);

// Move to the next table entry (+4 because the length itself is not inclusive)
current = current.add(len + 4);
}
}
}
Expand Down

0 comments on commit 7536093

Please sign in to comment.