Merge pull request #3323 from fitzgen/unwind-info-cleanups

Unwind info cleanups
This commit is contained in:
Nick Fitzgerald
2021-09-09 14:38:52 -07:00
committed by GitHub
4 changed files with 59 additions and 13 deletions

View File

@@ -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))
} }

View File

@@ -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 });

View File

@@ -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()

View File

@@ -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"
} }
} }