Merge pull request #3323 from fitzgen/unwind-info-cleanups
Unwind info cleanups
This commit is contained in:
@@ -271,6 +271,8 @@ impl wasmtime_environ::Compiler for Compiler {
|
|||||||
trampolines.push(builder.trampoline(*i, &func));
|
trampolines.push(builder.trampoline(*i, &func));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
builder.unwind_info();
|
||||||
|
|
||||||
if emit_dwarf && funcs.len() > 0 {
|
if emit_dwarf && funcs.len() > 0 {
|
||||||
let ofs = VMOffsets::new(
|
let ofs = VMOffsets::new(
|
||||||
self.isa
|
self.isa
|
||||||
@@ -330,6 +332,7 @@ impl wasmtime_environ::Compiler for Compiler {
|
|||||||
let mut builder = ObjectBuilder::new(obj, &module, &*self.isa);
|
let mut builder = ObjectBuilder::new(obj, &module, &*self.isa);
|
||||||
let a = builder.trampoline(SignatureIndex::new(0), &host_to_wasm);
|
let a = builder.trampoline(SignatureIndex::new(0), &host_to_wasm);
|
||||||
let b = builder.trampoline(SignatureIndex::new(1), &wasm_to_host);
|
let b = builder.trampoline(SignatureIndex::new(1), &wasm_to_host);
|
||||||
|
builder.unwind_info();
|
||||||
builder.finish()?;
|
builder.finish()?;
|
||||||
Ok((a, b))
|
Ok((a, b))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,9 @@ fn emit_dwarf_sections(
|
|||||||
sections.for_each_mut(|id, s| -> anyhow::Result<()> {
|
sections.for_each_mut(|id, s| -> anyhow::Result<()> {
|
||||||
let name = id.name();
|
let name = id.name();
|
||||||
let body = s.writer.take();
|
let body = s.writer.take();
|
||||||
|
if body.is_empty() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
let mut relocs = vec![];
|
let mut relocs = vec![];
|
||||||
::std::mem::swap(&mut relocs, &mut s.relocs);
|
::std::mem::swap(&mut relocs, &mut s.relocs);
|
||||||
result.push(DwarfSection { name, body, relocs });
|
result.push(DwarfSection { name, body, relocs });
|
||||||
|
|||||||
@@ -114,10 +114,14 @@ pub struct ObjectBuilder<'a> {
|
|||||||
/// a relocation against a libcall.
|
/// a relocation against a libcall.
|
||||||
libcalls: HashMap<LibCall, SymbolId>,
|
libcalls: HashMap<LibCall, SymbolId>,
|
||||||
|
|
||||||
|
windows_unwind_info_id: Option<SectionId>,
|
||||||
|
|
||||||
/// Packed form of windows unwind tables which, if present, will get emitted
|
/// Packed form of windows unwind tables which, if present, will get emitted
|
||||||
/// to a windows-specific unwind info section.
|
/// to a windows-specific unwind info section.
|
||||||
windows_unwind_info: Vec<RUNTIME_FUNCTION>,
|
windows_unwind_info: Vec<RUNTIME_FUNCTION>,
|
||||||
|
|
||||||
|
systemv_unwind_info_id: Option<SectionId>,
|
||||||
|
|
||||||
/// Pending unwinding information for DWARF-based platforms. This is used to
|
/// Pending unwinding information for DWARF-based platforms. This is used to
|
||||||
/// build a `.eh_frame` lookalike at the very end of object building.
|
/// build a `.eh_frame` lookalike at the very end of object building.
|
||||||
systemv_unwind_info: Vec<(u64, &'a systemv::UnwindInfo)>,
|
systemv_unwind_info: Vec<(u64, &'a systemv::UnwindInfo)>,
|
||||||
@@ -139,6 +143,11 @@ pub struct ObjectBuilder<'a> {
|
|||||||
/// In-progress text section that we're using cranelift's `MachBuffer` to
|
/// In-progress text section that we're using cranelift's `MachBuffer` to
|
||||||
/// build to resolve relocations (calls) between functions.
|
/// build to resolve relocations (calls) between functions.
|
||||||
pub text: Box<dyn TextSectionBuilder>,
|
pub text: Box<dyn TextSectionBuilder>,
|
||||||
|
|
||||||
|
/// The unwind info _must_ come directly after the text section. Our FDE's
|
||||||
|
/// instructions are encoded to rely on this placement. We use this `bool`
|
||||||
|
/// for debug assertions to ensure that we get the ordering correct.
|
||||||
|
added_unwind_info: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a mirror of `RUNTIME_FUNCTION` in the Windows API, but defined here
|
// This is a mirror of `RUNTIME_FUNCTION` in the Windows API, but defined here
|
||||||
@@ -190,7 +199,9 @@ impl<'a> ObjectBuilder<'a> {
|
|||||||
text_section,
|
text_section,
|
||||||
func_symbols,
|
func_symbols,
|
||||||
libcalls,
|
libcalls,
|
||||||
|
windows_unwind_info_id: None,
|
||||||
windows_unwind_info: Vec::new(),
|
windows_unwind_info: Vec::new(),
|
||||||
|
systemv_unwind_info_id: None,
|
||||||
systemv_unwind_info: Vec::new(),
|
systemv_unwind_info: Vec::new(),
|
||||||
relocations: Vec::new(),
|
relocations: Vec::new(),
|
||||||
text: match isa.get_mach_backend() {
|
text: match isa.get_mach_backend() {
|
||||||
@@ -199,6 +210,7 @@ impl<'a> ObjectBuilder<'a> {
|
|||||||
),
|
),
|
||||||
None => Box::new(DummyBuilder::default()),
|
None => Box::new(DummyBuilder::default()),
|
||||||
},
|
},
|
||||||
|
added_unwind_info: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,6 +344,7 @@ impl<'a> ObjectBuilder<'a> {
|
|||||||
///
|
///
|
||||||
/// This is expected to be called in-order for ascending `index` values.
|
/// This is expected to be called in-order for ascending `index` values.
|
||||||
pub fn func(&mut self, index: DefinedFuncIndex, func: &'a CompiledFunction) -> Range<u64> {
|
pub fn func(&mut self, index: DefinedFuncIndex, func: &'a CompiledFunction) -> Range<u64> {
|
||||||
|
assert!(!self.added_unwind_info);
|
||||||
let index = self.module.func_index(index);
|
let index = self.module.func_index(index);
|
||||||
let name = obj::func_symbol_name(index);
|
let name = obj::func_symbol_name(index);
|
||||||
let (symbol_id, range) = self.append_func(true, name.into_bytes(), func);
|
let (symbol_id, range) = self.append_func(true, name.into_bytes(), func);
|
||||||
@@ -340,6 +353,7 @@ impl<'a> ObjectBuilder<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn trampoline(&mut self, sig: SignatureIndex, func: &'a CompiledFunction) -> Trampoline {
|
pub fn trampoline(&mut self, sig: SignatureIndex, func: &'a CompiledFunction) -> Trampoline {
|
||||||
|
assert!(!self.added_unwind_info);
|
||||||
let name = obj::trampoline_symbol_name(sig);
|
let name = obj::trampoline_symbol_name(sig);
|
||||||
let (_, range) = self.append_func(false, name.into_bytes(), func);
|
let (_, range) = self.append_func(false, name.into_bytes(), func);
|
||||||
Trampoline {
|
Trampoline {
|
||||||
@@ -350,6 +364,11 @@ impl<'a> ObjectBuilder<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn dwarf_sections(&mut self, sections: &[DwarfSection]) -> Result<()> {
|
pub fn dwarf_sections(&mut self, sections: &[DwarfSection]) -> Result<()> {
|
||||||
|
assert!(
|
||||||
|
self.added_unwind_info,
|
||||||
|
"can't add dwarf yet; unwind info must directly follow the text section"
|
||||||
|
);
|
||||||
|
|
||||||
// If we have DWARF data, write it in the object file.
|
// If we have DWARF data, write it in the object file.
|
||||||
let (debug_bodies, debug_relocs): (Vec<_>, Vec<_>) = sections
|
let (debug_bodies, debug_relocs): (Vec<_>, Vec<_>) = sections
|
||||||
.iter()
|
.iter()
|
||||||
@@ -394,6 +413,29 @@ impl<'a> ObjectBuilder<'a> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn unwind_info(&mut self) {
|
||||||
|
assert!(!self.added_unwind_info);
|
||||||
|
|
||||||
|
if self.windows_unwind_info.len() > 0 {
|
||||||
|
let segment = self.obj.segment_name(StandardSegment::Data).to_vec();
|
||||||
|
self.windows_unwind_info_id = Some(self.obj.add_section(
|
||||||
|
segment,
|
||||||
|
b"_wasmtime_winx64_unwind".to_vec(),
|
||||||
|
SectionKind::ReadOnlyData,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if self.systemv_unwind_info.len() > 0 {
|
||||||
|
let segment = self.obj.segment_name(StandardSegment::Data).to_vec();
|
||||||
|
self.systemv_unwind_info_id = Some(self.obj.add_section(
|
||||||
|
segment,
|
||||||
|
b".eh_frame".to_vec(),
|
||||||
|
SectionKind::ReadOnlyData,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.added_unwind_info = true;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn finish(&mut self) -> Result<()> {
|
pub fn finish(&mut self) -> Result<()> {
|
||||||
// Now that all function symbols are available register all final
|
// Now that all function symbols are available register all final
|
||||||
// relocations between functions.
|
// relocations between functions.
|
||||||
@@ -438,6 +480,7 @@ impl<'a> ObjectBuilder<'a> {
|
|||||||
if self.systemv_unwind_info.len() > 0 {
|
if self.systemv_unwind_info.len() > 0 {
|
||||||
self.append_systemv_unwind_info();
|
self.append_systemv_unwind_info();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -454,17 +497,13 @@ impl<'a> ObjectBuilder<'a> {
|
|||||||
// This may need updates for other platforms.
|
// This may need updates for other platforms.
|
||||||
assert_eq!(self.obj.architecture(), Architecture::X86_64);
|
assert_eq!(self.obj.architecture(), Architecture::X86_64);
|
||||||
|
|
||||||
|
let section_id = self.windows_unwind_info_id.unwrap();
|
||||||
|
|
||||||
// Page-align the text section so the unwind info can reside on a
|
// Page-align the text section so the unwind info can reside on a
|
||||||
// separate page that doesn't need executable permissions.
|
// separate page that doesn't need executable permissions.
|
||||||
self.obj
|
self.obj
|
||||||
.append_section_data(self.text_section, &[], self.isa.code_section_alignment());
|
.append_section_data(self.text_section, &[], self.isa.code_section_alignment());
|
||||||
|
|
||||||
let segment = self.obj.segment_name(StandardSegment::Data).to_vec();
|
|
||||||
let section_id = self.obj.add_section(
|
|
||||||
segment,
|
|
||||||
b"_wasmtime_winx64_unwind".to_vec(),
|
|
||||||
SectionKind::ReadOnlyData,
|
|
||||||
);
|
|
||||||
let mut unwind_info = Vec::with_capacity(self.windows_unwind_info.len() * 3 * 4);
|
let mut unwind_info = Vec::with_capacity(self.windows_unwind_info.len() * 3 * 4);
|
||||||
for info in self.windows_unwind_info.iter() {
|
for info in self.windows_unwind_info.iter() {
|
||||||
unwind_info.extend_from_slice(&info.begin.to_le_bytes());
|
unwind_info.extend_from_slice(&info.begin.to_le_bytes());
|
||||||
@@ -513,12 +552,7 @@ impl<'a> ObjectBuilder<'a> {
|
|||||||
/// such as being purely read-only instead of read/execute like the code
|
/// such as being purely read-only instead of read/execute like the code
|
||||||
/// bits.
|
/// bits.
|
||||||
fn append_systemv_unwind_info(&mut self) {
|
fn append_systemv_unwind_info(&mut self) {
|
||||||
let segment = self.obj.segment_name(StandardSegment::Data).to_vec();
|
let section_id = self.systemv_unwind_info_id.unwrap();
|
||||||
let section_id = self.obj.add_section(
|
|
||||||
segment,
|
|
||||||
b"_wasmtime_eh_frame".to_vec(),
|
|
||||||
SectionKind::ReadOnlyData,
|
|
||||||
);
|
|
||||||
let mut cie = self
|
let mut cie = self
|
||||||
.isa
|
.isa
|
||||||
.create_systemv_cie()
|
.create_systemv_cie()
|
||||||
|
|||||||
@@ -25,6 +25,12 @@ impl UnwindRegistration {
|
|||||||
unwind_info: *mut u8,
|
unwind_info: *mut u8,
|
||||||
unwind_len: usize,
|
unwind_len: usize,
|
||||||
) -> Result<UnwindRegistration> {
|
) -> Result<UnwindRegistration> {
|
||||||
|
debug_assert_eq!(
|
||||||
|
unwind_info as usize % region::page::size(),
|
||||||
|
0,
|
||||||
|
"The unwind info must always be aligned to a page"
|
||||||
|
);
|
||||||
|
|
||||||
let mut registrations = Vec::new();
|
let mut registrations = Vec::new();
|
||||||
if cfg!(any(
|
if cfg!(any(
|
||||||
all(target_os = "linux", target_env = "gnu"),
|
all(target_os = "linux", target_env = "gnu"),
|
||||||
@@ -63,7 +69,7 @@ impl UnwindRegistration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn section_name() -> &'static str {
|
pub fn section_name() -> &'static str {
|
||||||
"_wasmtime_eh_frame"
|
".eh_frame"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user