Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
2811: Added some infrastructure to generate EH_Frame in singlepass compiler r=Amanieu a=ptitSeb

# Description
Add generation of EH_Frame in singlepass compiler, to allow correct backtrace in case of trap.

Co-authored-by: ptitSeb <[email protected]>
  • Loading branch information
bors[bot] and ptitSeb authored Mar 23, 2022
2 parents 5b77bc4 + dec097e commit a8a3412
Show file tree
Hide file tree
Showing 15 changed files with 1,008 additions and 36 deletions.
6 changes: 6 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion lib/compiler-singlepass/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ wasmer-vm = { path = "../vm", version = "=2.2.1" }
wasmer-types = { path = "../types", version = "=2.2.1", default-features = false, features = ["std"] }
rayon = { version = "1.5", optional = true }
hashbrown = { version = "0.11", optional = true }
gimli = { version = "0.26", optional = true }
more-asserts = "0.2"
dynasm = "1.2.1"
dynasmrt = "1.2.1"
Expand All @@ -32,8 +33,9 @@ target-lexicon = { version = "0.12.2", default-features = false }
maintenance = { status = "actively-developed" }

[features]
default = ["std", "rayon", "avx"]
default = ["std", "rayon", "unwind", "avx"]
std = ["wasmer-compiler/std", "wasmer-types/std"]
core = ["hashbrown", "wasmer-types/core"]
unwind = ["gimli"]
sse = []
avx = []
6 changes: 6 additions & 0 deletions lib/compiler-singlepass/src/arm64_decl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,9 @@ impl AbstractReg for GPR {
];
GPRS.iter()
}
fn to_dwarf(self) -> u16 {
self.into_index() as u16
}
}

impl AbstractReg for NEON {
Expand Down Expand Up @@ -196,6 +199,9 @@ impl AbstractReg for NEON {
];
NEONS.iter()
}
fn to_dwarf(self) -> u16 {
self.into_index() as u16 + 64
}
}

/// A machine register under the x86-64 architecture.
Expand Down
58 changes: 46 additions & 12 deletions lib/compiler-singlepass/src/codegen.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
use crate::address_map::get_function_address_map;
#[cfg(feature = "unwind")]
use crate::dwarf::WriterRelocate;
use crate::location::{Location, Reg};
use crate::machine::{CodegenError, Label, Machine, MachineStackOffset, NATIVE_PAGE_SIZE};
use crate::unwind::UnwindFrame;
use crate::{common_decl::*, config::Singlepass};
#[cfg(feature = "unwind")]
use gimli::write::Address;
use smallvec::{smallvec, SmallVec};
use std::cmp;
use std::iter;
use wasmer_compiler::wasmparser::{Operator, Type as WpType, TypeOrFuncType as WpTypeOrFuncType};
#[cfg(feature = "unwind")]
use wasmer_compiler::CompiledFunctionUnwindInfo;
use wasmer_compiler::{
CallingConvention, CompiledFunction, CompiledFunctionFrameInfo, FunctionBody, FunctionBodyData,
Relocation, RelocationTarget, SectionIndex,
Expand Down Expand Up @@ -5852,7 +5859,7 @@ impl<'a, M: Machine> FuncGen<'a, M> {
Ok(())
}

pub fn finalize(mut self, data: &FunctionBodyData) -> CompiledFunction {
pub fn finalize(mut self, data: &FunctionBodyData) -> (CompiledFunction, Option<UnwindFrame>) {
// Generate actual code for special labels.
self.machine
.emit_label(self.special_labels.integer_division_by_zero);
Expand Down Expand Up @@ -5892,23 +5899,50 @@ impl<'a, M: Machine> FuncGen<'a, M> {
self.machine.finalize_function();

let body_len = self.machine.assembler_get_offset().0;

let mut unwind_info = None;
let mut fde = None;
#[cfg(feature = "unwind")]
match self.calling_convention {
CallingConvention::SystemV | CallingConvention::AppleAarch64 => {
let unwind = self.machine.gen_dwarf_unwind_info(body_len);
if let Some(unwind) = unwind {
fde = Some(unwind.to_fde(Address::Symbol {
symbol: WriterRelocate::FUNCTION_SYMBOL,
addend: self.fsm.local_function_id as _,
}));
unwind_info = Some(CompiledFunctionUnwindInfo::Dwarf);
}
}
CallingConvention::WindowsFastcall => {
let unwind = self.machine.gen_windows_unwind_info(body_len);
if let Some(unwind) = unwind {
unwind_info = Some(CompiledFunctionUnwindInfo::WindowsX64(unwind));
}
}
_ => (),
};

let address_map =
get_function_address_map(self.machine.instructions_address_map(), data, body_len);
let traps = self.machine.collect_trap_information();
let body = self.machine.assembler_finalize();

CompiledFunction {
body: FunctionBody {
body: body,
unwind_info: None,
},
relocations: self.relocations.clone(),
jt_offsets: SecondaryMap::new(),
frame_info: CompiledFunctionFrameInfo {
traps: traps,
address_map,
(
CompiledFunction {
body: FunctionBody {
body: body,
unwind_info,
},
relocations: self.relocations.clone(),
jt_offsets: SecondaryMap::new(),
frame_info: CompiledFunctionFrameInfo {
traps: traps,
address_map,
},
},
}
fde,
)
}
// FIXME: This implementation seems to be not enough to resolve all kinds of register dependencies
// at call place.
Expand Down
71 changes: 61 additions & 10 deletions lib/compiler-singlepass/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,28 @@

use crate::codegen::FuncGen;
use crate::config::Singlepass;
#[cfg(feature = "unwind")]
use crate::dwarf::WriterRelocate;
use crate::machine::Machine;
use crate::machine::{
gen_import_call_trampoline, gen_std_dynamic_import_trampoline, gen_std_trampoline, CodegenError,
};
use crate::machine_arm64::MachineARM64;
use crate::machine_x64::MachineX86_64;
#[cfg(feature = "unwind")]
use crate::unwind::{create_systemv_cie, UnwindFrame};
#[cfg(feature = "unwind")]
use gimli::write::{EhFrame, FrameTable};
use loupe::MemoryUsage;
#[cfg(feature = "rayon")]
use rayon::prelude::{IntoParallelIterator, ParallelIterator};
use std::sync::Arc;
use wasmer_compiler::{
Architecture, CallingConvention, Compilation, CompileError, CompileModuleInfo,
CompiledFunction, Compiler, CompilerConfig, CpuFeature, FunctionBinaryReader, FunctionBody,
FunctionBodyData, MiddlewareBinaryReader, ModuleMiddleware, ModuleMiddlewareChain,
ModuleTranslationState, OperatingSystem, SectionIndex, Target, TrapInformation,
CompiledFunction, Compiler, CompilerConfig, CpuFeature, Dwarf, FunctionBinaryReader,
FunctionBody, FunctionBodyData, MiddlewareBinaryReader, ModuleMiddleware,
ModuleMiddlewareChain, ModuleTranslationState, OperatingSystem, SectionIndex, Target,
TrapInformation,
};
use wasmer_types::entity::{EntityRef, PrimaryMap};
use wasmer_types::{
Expand Down Expand Up @@ -94,11 +101,34 @@ impl Compiler for SinglepassCompiler {
_ => panic!("Unsupported Calling convention for Singlepass compiler"),
};

// Generate the frametable
#[cfg(feature = "unwind")]
let dwarf_frametable = if function_body_inputs.is_empty() {
// If we have no function body inputs, we don't need to
// construct the `FrameTable`. Constructing it, with empty
// FDEs will cause some issues in Linux.
None
} else {
match target.triple().default_calling_convention() {
Ok(CallingConvention::SystemV) => {
match create_systemv_cie(target.triple().architecture) {
Some(cie) => {
let mut dwarf_frametable = FrameTable::default();
let cie_id = dwarf_frametable.add_cie(cie);
Some((dwarf_frametable, cie_id))
}
None => None,
}
}
_ => None,
}
};

let memory_styles = &compile_info.memory_styles;
let table_styles = &compile_info.table_styles;
let vmoffsets = VMOffsets::new(8, &compile_info.module);
let module = &compile_info.module;
let import_trampolines: PrimaryMap<SectionIndex, _> = (0..module.num_imported_functions)
let mut custom_sections: PrimaryMap<SectionIndex, _> = (0..module.num_imported_functions)
.map(FunctionIndex::new)
.collect::<Vec<_>>()
.into_par_iter_if_rayon()
Expand All @@ -114,7 +144,7 @@ impl Compiler for SinglepassCompiler {
.collect::<Vec<_>>()
.into_iter()
.collect();
let functions = function_body_inputs
let (functions, fdes): (Vec<CompiledFunction>, Vec<_>) = function_body_inputs
.iter()
.collect::<Vec<(LocalFunctionIndex, &FunctionBodyData<'_>)>>()
.into_par_iter_if_rayon()
Expand Down Expand Up @@ -185,9 +215,9 @@ impl Compiler for SinglepassCompiler {
_ => unimplemented!(),
}
})
.collect::<Result<Vec<CompiledFunction>, CompileError>>()?
.collect::<Result<Vec<_>, CompileError>>()?
.into_iter()
.collect::<PrimaryMap<LocalFunctionIndex, CompiledFunction>>();
.unzip();

let function_call_trampolines = module
.signatures
Expand Down Expand Up @@ -215,12 +245,33 @@ impl Compiler for SinglepassCompiler {
.into_iter()
.collect::<PrimaryMap<FunctionIndex, FunctionBody>>();

#[cfg(feature = "unwind")]
let dwarf = if let Some((mut dwarf_frametable, cie_id)) = dwarf_frametable {
for fde in fdes {
if let Some(fde) = fde {
match fde {
UnwindFrame::SystemV(fde) => dwarf_frametable.add_fde(cie_id, fde),
}
}
}
let mut eh_frame = EhFrame(WriterRelocate::new(target.triple().endianness().ok()));
dwarf_frametable.write_eh_frame(&mut eh_frame).unwrap();

let eh_frame_section = eh_frame.0.into_section();
custom_sections.push(eh_frame_section);
Some(Dwarf::new(SectionIndex::new(custom_sections.len() - 1)))
} else {
None
};
#[cfg(not(feature = "unwind"))]
let dwarf = None;

Ok(Compilation::new(
functions,
import_trampolines,
functions.into_iter().collect(),
custom_sections,
function_call_trampolines,
dynamic_function_trampolines,
None,
dwarf,
))
}
}
Expand Down
102 changes: 102 additions & 0 deletions lib/compiler-singlepass/src/dwarf.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
use gimli::write::{Address, EndianVec, Result, Writer};
use gimli::{RunTimeEndian, SectionId};
use wasmer_compiler::{CustomSection, CustomSectionProtection, SectionBody};
use wasmer_compiler::{Endianness, Relocation, RelocationKind, RelocationTarget};
use wasmer_types::entity::EntityRef;
use wasmer_types::LocalFunctionIndex;

#[derive(Clone, Debug)]
pub struct WriterRelocate {
pub relocs: Vec<Relocation>,
writer: EndianVec<RunTimeEndian>,
}

impl WriterRelocate {
pub const FUNCTION_SYMBOL: usize = 0;
pub fn new(endianness: Option<Endianness>) -> Self {
let endianness = match endianness {
Some(Endianness::Little) => RunTimeEndian::Little,
Some(Endianness::Big) => RunTimeEndian::Big,
// We autodetect it, based on the host
None => RunTimeEndian::default(),
};
WriterRelocate {
relocs: Vec::new(),
writer: EndianVec::new(endianness),
}
}

pub fn into_section(mut self) -> CustomSection {
// GCC expects a terminating "empty" length, so write a 0 length at the end of the table.
self.writer.write_u32(0).unwrap();
let data = self.writer.into_vec();
CustomSection {
protection: CustomSectionProtection::Read,
bytes: SectionBody::new_with_vec(data),
relocations: self.relocs,
}
}
}

impl Writer for WriterRelocate {
type Endian = RunTimeEndian;

fn endian(&self) -> Self::Endian {
self.writer.endian()
}

fn len(&self) -> usize {
self.writer.len()
}

fn write(&mut self, bytes: &[u8]) -> Result<()> {
self.writer.write(bytes)
}

fn write_at(&mut self, offset: usize, bytes: &[u8]) -> Result<()> {
self.writer.write_at(offset, bytes)
}

fn write_address(&mut self, address: Address, size: u8) -> Result<()> {
match address {
Address::Constant(val) => self.write_udata(val, size),
Address::Symbol { symbol, addend } => {
// Is a function relocation
if symbol == Self::FUNCTION_SYMBOL {
// We use the addend to detect the function index
let function_index = LocalFunctionIndex::new(addend as _);
let reloc_target = RelocationTarget::LocalFunc(function_index);
let offset = self.len() as u32;
let kind = match size {
8 => RelocationKind::Abs8,
_ => unimplemented!("dwarf relocation size not yet supported: {}", size),
};
let addend = 0;
self.relocs.push(Relocation {
kind,
reloc_target,
offset,
addend,
});
self.write_udata(addend as u64, size)
} else {
unreachable!("Symbol {} in DWARF not recognized", symbol);
}
}
}
}

fn write_offset(&mut self, _val: usize, _section: SectionId, _size: u8) -> Result<()> {
unimplemented!("write_offset not yet implemented");
}

fn write_offset_at(
&mut self,
_offset: usize,
_val: usize,
_section: SectionId,
_size: u8,
) -> Result<()> {
unimplemented!("write_offset_at not yet implemented");
}
}
5 changes: 5 additions & 0 deletions lib/compiler-singlepass/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,17 @@ mod codegen;
mod common_decl;
mod compiler;
mod config;
#[cfg(feature = "unwind")]
mod dwarf;
mod emitter_arm64;
mod emitter_x64;
mod location;
mod machine;
mod machine_arm64;
mod machine_x64;
mod unwind;
#[cfg(feature = "unwind")]
mod unwind_winx64;
mod x64_decl;

pub use crate::compiler::SinglepassCompiler;
Expand Down
Loading

0 comments on commit a8a3412

Please sign in to comment.