mirror of
https://github.com/mii443/wasmer.git
synced 2025-09-03 16:09:20 +00:00
Cranelift in Unix working all the way with unwind info
This commit is contained in:
@ -17,9 +17,7 @@ use cranelift_codegen::ir;
|
|||||||
use cranelift_codegen::print_errors::pretty_error;
|
use cranelift_codegen::print_errors::pretty_error;
|
||||||
use cranelift_codegen::{binemit, isa, Context};
|
use cranelift_codegen::{binemit, isa, Context};
|
||||||
#[cfg(feature = "unwind")]
|
#[cfg(feature = "unwind")]
|
||||||
use gimli::write::{Address, EhFrame, EndianVec, FrameTable, Sections, Writer};
|
use gimli::write::{Address, EhFrame, FrameTable};
|
||||||
#[cfg(feature = "unwind")]
|
|
||||||
use gimli::{RunTimeEndian, SectionId};
|
|
||||||
use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};
|
use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};
|
||||||
use wasm_common::entity::{EntityRef, PrimaryMap};
|
use wasm_common::entity::{EntityRef, PrimaryMap};
|
||||||
use wasm_common::{
|
use wasm_common::{
|
||||||
@ -189,6 +187,7 @@ impl Compiler for CraneliftCompiler {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.collect::<PrimaryMap<LocalFunctionIndex, _>>();
|
.collect::<PrimaryMap<LocalFunctionIndex, _>>();
|
||||||
|
|
||||||
|
let mut custom_sections = PrimaryMap::new();
|
||||||
let mut eh_frame = EhFrame(WriterRelocate::default());
|
let mut eh_frame = EhFrame(WriterRelocate::default());
|
||||||
dwarf_frametable
|
dwarf_frametable
|
||||||
.lock()
|
.lock()
|
||||||
@ -197,9 +196,6 @@ impl Compiler for CraneliftCompiler {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let eh_frame_section = eh_frame.0.into_section();
|
let eh_frame_section = eh_frame.0.into_section();
|
||||||
println!("section: {:?}", eh_frame_section);
|
|
||||||
|
|
||||||
let mut custom_sections = PrimaryMap::new();
|
|
||||||
custom_sections.push(eh_frame_section);
|
custom_sections.push(eh_frame_section);
|
||||||
|
|
||||||
let dwarf = Dwarf::new(SectionIndex::new(0));
|
let dwarf = Dwarf::new(SectionIndex::new(0));
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use gimli::write::{Address, Dwarf, EndianVec, FrameTable, Result, Sections, Writer};
|
use gimli::write::{Address, EndianVec, Result, Writer};
|
||||||
use gimli::{RunTimeEndian, SectionId};
|
use gimli::{RunTimeEndian, SectionId};
|
||||||
use wasm_common::entity::EntityRef;
|
use wasm_common::entity::EntityRef;
|
||||||
use wasm_common::LocalFunctionIndex;
|
use wasm_common::LocalFunctionIndex;
|
||||||
@ -84,7 +84,7 @@ impl Writer for WriterRelocate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_offset(&mut self, val: usize, section: SectionId, size: u8) -> Result<()> {
|
fn write_offset(&mut self, _val: usize, _section: SectionId, _size: u8) -> Result<()> {
|
||||||
unimplemented!("write_offset not yet implemented");
|
unimplemented!("write_offset not yet implemented");
|
||||||
// let offset = self.len() as u32;
|
// let offset = self.len() as u32;
|
||||||
// let target = section.name().to_string();
|
// let target = section.name().to_string();
|
||||||
@ -99,10 +99,10 @@ impl Writer for WriterRelocate {
|
|||||||
|
|
||||||
fn write_offset_at(
|
fn write_offset_at(
|
||||||
&mut self,
|
&mut self,
|
||||||
offset: usize,
|
_offset: usize,
|
||||||
val: usize,
|
_val: usize,
|
||||||
section: SectionId,
|
_section: SectionId,
|
||||||
size: u8,
|
_size: u8,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
unimplemented!("write_offset_at not yet implemented");
|
unimplemented!("write_offset_at not yet implemented");
|
||||||
// let target = section.name().to_string();
|
// let target = section.name().to_string();
|
||||||
|
@ -77,12 +77,12 @@ pub type CustomSections = PrimaryMap<SectionIndex, CustomSection>;
|
|||||||
/// In the future this structure may also hold other information useful
|
/// In the future this structure may also hold other information useful
|
||||||
/// for debugging.
|
/// for debugging.
|
||||||
#[cfg_attr(feature = "enable-serde", derive(Deserialize, Serialize))]
|
#[cfg_attr(feature = "enable-serde", derive(Deserialize, Serialize))]
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
pub struct Dwarf {
|
pub struct Dwarf {
|
||||||
/// The section index in the [`Compilation`] that corresponds to the exception frames.
|
/// The section index in the [`Compilation`] that corresponds to the exception frames.
|
||||||
/// More info:
|
/// More info:
|
||||||
/// https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html
|
/// https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html
|
||||||
eh_frame: SectionIndex,
|
pub eh_frame: SectionIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Dwarf {
|
impl Dwarf {
|
||||||
@ -179,6 +179,11 @@ impl Compilation {
|
|||||||
.map(|(_, section)| section.relocations.clone())
|
.map(|(_, section)| section.relocations.clone())
|
||||||
.collect::<PrimaryMap<SectionIndex, _>>()
|
.collect::<PrimaryMap<SectionIndex, _>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the Dwarf info.
|
||||||
|
pub fn get_dwarf(&self) -> Option<Dwarf> {
|
||||||
|
self.dwarf.clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> IntoIterator for &'a Compilation {
|
impl<'a> IntoIterator for &'a Compilation {
|
||||||
|
@ -118,6 +118,7 @@ impl JITArtifact {
|
|||||||
dynamic_function_trampolines,
|
dynamic_function_trampolines,
|
||||||
custom_sections: compilation.get_custom_sections(),
|
custom_sections: compilation.get_custom_sections(),
|
||||||
custom_section_relocations: compilation.get_custom_section_relocations(),
|
custom_section_relocations: compilation.get_custom_section_relocations(),
|
||||||
|
dwarf: compilation.get_dwarf(),
|
||||||
};
|
};
|
||||||
let serializable = SerializableModule {
|
let serializable = SerializableModule {
|
||||||
compilation: serializable_compilation,
|
compilation: serializable_compilation,
|
||||||
@ -191,8 +192,21 @@ impl JITArtifact {
|
|||||||
.collect::<PrimaryMap<_, _>>()
|
.collect::<PrimaryMap<_, _>>()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let eh_frame = match &serializable.compilation.dwarf {
|
||||||
|
Some(dwarf) => {
|
||||||
|
let eh_frame_section_size = serializable.compilation.custom_sections
|
||||||
|
[dwarf.eh_frame]
|
||||||
|
.bytes
|
||||||
|
.len();
|
||||||
|
let eh_frame_section_pointer = custom_sections[dwarf.eh_frame];
|
||||||
|
Some(unsafe {
|
||||||
|
std::slice::from_raw_parts(eh_frame_section_pointer, eh_frame_section_size)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
// Make all code compiled thus far executable.
|
// Make all code compiled thus far executable.
|
||||||
inner_jit.publish_compiled_code();
|
inner_jit.publish_compiled_code(eh_frame);
|
||||||
|
|
||||||
let finished_functions = finished_functions.into_boxed_slice();
|
let finished_functions = finished_functions.into_boxed_slice();
|
||||||
let finished_dynamic_function_trampolines =
|
let finished_dynamic_function_trampolines =
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
use crate::unwind::UnwindRegistry;
|
use crate::unwind::UnwindRegistry;
|
||||||
use region;
|
use region;
|
||||||
use std::mem::ManuallyDrop;
|
use std::mem::ManuallyDrop;
|
||||||
use std::ptr;
|
|
||||||
use std::{cmp, mem};
|
use std::{cmp, mem};
|
||||||
use wasm_common::entity::PrimaryMap;
|
use wasm_common::entity::PrimaryMap;
|
||||||
use wasm_common::LocalFunctionIndex;
|
use wasm_common::LocalFunctionIndex;
|
||||||
@ -140,7 +139,7 @@ impl CodeMemory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Make all allocated memory executable.
|
/// Make all allocated memory executable.
|
||||||
pub fn publish(&mut self) {
|
pub fn publish(&mut self, eh_frame: Option<&[u8]>) {
|
||||||
self.push_current(0)
|
self.push_current(0)
|
||||||
.expect("failed to push current memory map");
|
.expect("failed to push current memory map");
|
||||||
|
|
||||||
@ -150,7 +149,7 @@ impl CodeMemory {
|
|||||||
} in &mut self.entries[self.published..]
|
} in &mut self.entries[self.published..]
|
||||||
{
|
{
|
||||||
// Remove write access to the pages due to the relocation fixups.
|
// Remove write access to the pages due to the relocation fixups.
|
||||||
r.publish()
|
r.publish(eh_frame)
|
||||||
.expect("failed to publish function unwind registry");
|
.expect("failed to publish function unwind registry");
|
||||||
|
|
||||||
if !m.is_empty() {
|
if !m.is_empty() {
|
||||||
|
@ -248,8 +248,8 @@ impl JITEngineInner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Make memory containing compiled code executable.
|
/// Make memory containing compiled code executable.
|
||||||
pub(crate) fn publish_compiled_code(&mut self) {
|
pub(crate) fn publish_compiled_code(&mut self, eh_frame: Option<&[u8]>) {
|
||||||
self.code_memory.publish();
|
self.code_memory.publish(eh_frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shared signature registry.
|
/// Shared signature registry.
|
||||||
|
@ -5,7 +5,9 @@ use wasm_common::{
|
|||||||
Features, FunctionIndex, LocalFunctionIndex, MemoryIndex, OwnedDataInitializer, SignatureIndex,
|
Features, FunctionIndex, LocalFunctionIndex, MemoryIndex, OwnedDataInitializer, SignatureIndex,
|
||||||
TableIndex,
|
TableIndex,
|
||||||
};
|
};
|
||||||
use wasmer_compiler::{CustomSection, FunctionBody, JumpTableOffsets, Relocation, SectionIndex};
|
use wasmer_compiler::{
|
||||||
|
CustomSection, Dwarf, FunctionBody, JumpTableOffsets, Relocation, SectionIndex,
|
||||||
|
};
|
||||||
use wasmer_engine::SerializableFunctionFrameInfo;
|
use wasmer_engine::SerializableFunctionFrameInfo;
|
||||||
use wasmer_runtime::ModuleInfo;
|
use wasmer_runtime::ModuleInfo;
|
||||||
use wasmer_runtime::{MemoryPlan, TablePlan};
|
use wasmer_runtime::{MemoryPlan, TablePlan};
|
||||||
@ -24,6 +26,8 @@ pub struct SerializableCompilation {
|
|||||||
pub dynamic_function_trampolines: PrimaryMap<FunctionIndex, FunctionBody>,
|
pub dynamic_function_trampolines: PrimaryMap<FunctionIndex, FunctionBody>,
|
||||||
pub custom_sections: PrimaryMap<SectionIndex, CustomSection>,
|
pub custom_sections: PrimaryMap<SectionIndex, CustomSection>,
|
||||||
pub custom_section_relocations: PrimaryMap<SectionIndex, Vec<Relocation>>,
|
pub custom_section_relocations: PrimaryMap<SectionIndex, Vec<Relocation>>,
|
||||||
|
// The section corresponding to the Dwarf debug infos
|
||||||
|
pub dwarf: Option<Dwarf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Serializable struct that is able to serialize from and to
|
/// Serializable struct that is able to serialize from and to
|
||||||
|
@ -24,7 +24,7 @@ impl DummyUnwindRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Publishes all registered functions.
|
/// Publishes all registered functions.
|
||||||
pub fn publish(&mut self) -> Result<(), String> {
|
pub fn publish(&mut self, eh_frame: Option<&[u8]>) -> Result<(), String> {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -2,15 +2,12 @@ cfg_if::cfg_if! {
|
|||||||
if #[cfg(all(windows, target_arch = "x86_64"))] {
|
if #[cfg(all(windows, target_arch = "x86_64"))] {
|
||||||
mod windows_x64;
|
mod windows_x64;
|
||||||
pub use self::windows_x64::*;
|
pub use self::windows_x64::*;
|
||||||
} else if #[cfg(all(windows, target_arch = "x86"))] {
|
} else if #[cfg(unix)] {
|
||||||
mod windows_x32;
|
mod systemv;
|
||||||
pub use self::windows_x32::*;
|
pub use self::systemv::*;
|
||||||
// } else if #[cfg(unix)] {
|
|
||||||
// mod systemv;
|
|
||||||
// pub use self::systemv::*;
|
|
||||||
} else {
|
} else {
|
||||||
|
// Otherwise, we provide a dummy fallback without unwinding
|
||||||
mod dummy;
|
mod dummy;
|
||||||
pub use self::dummy::DummyUnwindRegistry as UnwindRegistry;
|
pub use self::dummy::DummyUnwindRegistry as UnwindRegistry;
|
||||||
// compile_error!("unsupported target platform for unwind");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,6 @@ use wasmer_compiler::CompiledFunctionUnwindInfo;
|
|||||||
|
|
||||||
/// Represents a registry of function unwind information for System V ABI.
|
/// Represents a registry of function unwind information for System V ABI.
|
||||||
pub struct UnwindRegistry {
|
pub struct UnwindRegistry {
|
||||||
base_address: usize,
|
|
||||||
functions: Vec<gimli::write::FrameDescriptionEntry>,
|
|
||||||
frame_table: Vec<u8>,
|
|
||||||
registrations: Vec<usize>,
|
registrations: Vec<usize>,
|
||||||
published: bool,
|
published: bool,
|
||||||
}
|
}
|
||||||
@ -18,35 +15,33 @@ extern "C" {
|
|||||||
|
|
||||||
impl UnwindRegistry {
|
impl UnwindRegistry {
|
||||||
/// Creates a new unwind registry with the given base address.
|
/// Creates a new unwind registry with the given base address.
|
||||||
pub fn new(base_address: usize) -> Self {
|
pub fn new(_base_address: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
base_address,
|
|
||||||
functions: Vec::new(),
|
|
||||||
frame_table: Vec::new(),
|
|
||||||
registrations: Vec::new(),
|
registrations: Vec::new(),
|
||||||
published: false,
|
published: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Registers a function given the start offset, length, and unwind information.
|
/// Registers a function given the start offset, length, and unwind information.
|
||||||
pub fn register(&mut self, _func_start: u32, _func_len: u32, _info: &CompiledFunctionUnwindInfo) -> Result<(), String> {
|
pub fn register(
|
||||||
// Do nothing
|
&mut self,
|
||||||
|
_func_start: u32,
|
||||||
|
_func_len: u32,
|
||||||
|
info: &CompiledFunctionUnwindInfo,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
match info {
|
||||||
|
CompiledFunctionUnwindInfo::Dwarf => {}
|
||||||
|
_ => return Err("unsupported unwind information".to_string()),
|
||||||
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Publishes all registered functions.
|
/// Publishes all registered functions.
|
||||||
pub fn publish(&mut self, isa: &dyn TargetIsa) -> Result<()> {
|
pub fn publish(&mut self, eh_frame: Option<&[u8]>) -> Result<(), String> {
|
||||||
if self.published {
|
if let Some(eh_frame) = eh_frame {
|
||||||
bail!("unwind registry has already been published");
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.functions.is_empty() {
|
|
||||||
self.published = true;
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
self.register_frames();
|
self.register_frames(eh_frame);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.published = true;
|
self.published = true;
|
||||||
@ -54,13 +49,13 @@ impl UnwindRegistry {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::cast_ptr_alignment)]
|
||||||
unsafe fn register_frames(&mut self) {
|
unsafe fn register_frames(&mut self, eh_frame: &[u8]) {
|
||||||
cfg_if::cfg_if! {
|
cfg_if::cfg_if! {
|
||||||
if #[cfg(target_os = "macos")] {
|
if #[cfg(target_os = "macos")] {
|
||||||
// On macOS, `__register_frame` takes a pointer to a single FDE
|
// On macOS, `__register_frame` takes a pointer to a single FDE
|
||||||
let start = self.frame_table.as_ptr();
|
let start = eh_frame.as_ptr();
|
||||||
let end = start.add(self.frame_table.len());
|
let end = start.add(eh_frame.len());
|
||||||
let mut current = start;
|
let mut current = start;
|
||||||
|
|
||||||
// Walk all of the entries in the frame table and register them
|
// Walk all of the entries in the frame table and register them
|
||||||
@ -78,7 +73,7 @@ impl UnwindRegistry {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// On other platforms, `__register_frame` will walk the FDEs until an entry of length 0
|
// On other platforms, `__register_frame` will walk the FDEs until an entry of length 0
|
||||||
let ptr = self.frame_table.as_ptr();
|
let ptr = eh_frame.as_ptr();
|
||||||
__register_frame(ptr);
|
__register_frame(ptr);
|
||||||
self.registrations.push(ptr as usize);
|
self.registrations.push(ptr as usize);
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,10 @@ impl UnwindRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match info {
|
match info {
|
||||||
CompiledFunctionUnwindInfo::WindowsX64(_) => {
|
CompiledFunctionUnwindInfo::WindowsX64(_) => {}
|
||||||
|
_ => return Err("unsupported unwind information".to_string()),
|
||||||
|
};
|
||||||
|
|
||||||
let mut entry = winnt::RUNTIME_FUNCTION::default();
|
let mut entry = winnt::RUNTIME_FUNCTION::default();
|
||||||
|
|
||||||
entry.BeginAddress = func_start;
|
entry.BeginAddress = func_start;
|
||||||
@ -48,12 +51,9 @@ impl UnwindRegistry {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => Err("unsupported unwind information".to_string()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Publishes all registered functions.
|
/// Publishes all registered functions.
|
||||||
pub fn publish(&mut self) -> Result<(), String> {
|
pub fn publish(&mut self, _eh_frame: Option<&[u8]>) -> Result<(), String> {
|
||||||
if self.published {
|
if self.published {
|
||||||
return Err("unwind registry has already been published".to_string());
|
return Err("unwind registry has already been published".to_string());
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user