diff options
| author | bjorn3 <bjorn3@users.noreply.github.com> | 2020-05-01 20:57:51 +0200 |
|---|---|---|
| committer | bjorn3 <bjorn3@users.noreply.github.com> | 2020-05-01 20:58:27 +0200 |
| commit | 020bcb31dbb1e6a96575806a560bdc082bfa2bb6 (patch) | |
| tree | a3ace80021ada249422d23f52af0b4c49d1608e7 /src/debuginfo | |
| parent | 4da6488d95cec9709bf77a28913c8040cc0508ee (diff) | |
| download | rust-020bcb31dbb1e6a96575806a560bdc082bfa2bb6.tar.gz rust-020bcb31dbb1e6a96575806a560bdc082bfa2bb6.zip | |
Register frame table in JIT mode
Diffstat (limited to 'src/debuginfo')
| -rw-r--r-- | src/debuginfo/emit.rs | 21 | ||||
| -rw-r--r-- | src/debuginfo/unwind.rs | 85 |
2 files changed, 106 insertions, 0 deletions
diff --git a/src/debuginfo/emit.rs b/src/debuginfo/emit.rs index af93620fa8a..9cce630fed5 100644 --- a/src/debuginfo/emit.rs +++ b/src/debuginfo/emit.rs @@ -1,3 +1,5 @@ +use std::convert::TryInto; + use rustc_data_structures::fx::FxHashMap; use gimli::write::{Address, AttributeValue, EndianVec, Result, Sections, Writer}; @@ -67,6 +69,25 @@ impl WriterRelocate { writer: EndianVec::new(endian), } } + + pub(super) fn relocate_for_jit( + mut self, + jit_module: &mut cranelift_module::Module<cranelift_simplejit::SimpleJITBackend>, + ) -> Vec<u8> { + for reloc in self.relocs.drain(..) { + match reloc.name { + super::DebugRelocName::Section(_) => unreachable!(), + super::DebugRelocName::Symbol(sym) => { + let addr = jit_module.get_finalized_function( + cranelift_module::FuncId::from_u32(sym.try_into().unwrap()), + ); + let val = (addr as u64 as i64 + reloc.addend) as u64; + self.writer.write_udata_at(reloc.offset as usize, val, reloc.size).unwrap(); + } + } + } + self.writer.into_vec() + } } impl Writer for WriterRelocate { diff --git a/src/debuginfo/unwind.rs b/src/debuginfo/unwind.rs index 987c4d8f3e8..83795961377 100644 --- a/src/debuginfo/unwind.rs +++ b/src/debuginfo/unwind.rs @@ -64,4 +64,89 @@ impl<'tcx> UnwindContext<'tcx> { } } } + + pub(crate) unsafe fn register_jit( + self, + jit_module: &mut Module<cranelift_simplejit::SimpleJITBackend>, + ) -> Option<UnwindRegistry> { + let mut eh_frame = EhFrame::from(super::emit::WriterRelocate::new(super::target_endian(self.tcx))); + self.frame_table.write_eh_frame(&mut eh_frame).unwrap(); + + if eh_frame.0.writer.slice().is_empty() { + return None; + } + + let mut eh_frame = eh_frame.0.relocate_for_jit(jit_module); + + // GCC expects a terminating "empty" length, so write a 0 length at the end of the table. + eh_frame.extend(&[0, 0, 0, 0]); + + let mut registrations = Vec::new(); + + // ======================================================================= + // Everything after this line up to the end of the file is loosly based on + // https://github.com/bytecodealliance/wasmtime/blob/4471a82b0c540ff48960eca6757ccce5b1b5c3e4/crates/jit/src/unwind/systemv.rs + cfg_if::cfg_if! { + if #[cfg(target_os = "macos")] { + // On macOS, `__register_frame` takes a pointer to a single FDE + let start = eh_frame.as_ptr(); + let end = start.add(eh_frame.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); + registrations.push(current as usize); + } + + // Move to the next table entry (+4 because the length itself is not inclusive) + current = current.add(len + 4); + } + } else { + // On other platforms, `__register_frame` will walk the FDEs until an entry of length 0 + let ptr = eh_frame.as_ptr(); + __register_frame(ptr); + registrations.push(ptr as usize); + } + } + + Some(UnwindRegistry { + _frame_table: eh_frame, + registrations, + }) + } +} + +/// Represents a registry of function unwind information for System V ABI. +pub(crate) struct UnwindRegistry { + _frame_table: Vec<u8>, + registrations: Vec<usize>, +} + +extern "C" { + // libunwind import + fn __register_frame(fde: *const u8); + fn __deregister_frame(fde: *const u8); +} + +impl Drop for UnwindRegistry { + fn drop(&mut self) { + unsafe { + // libgcc stores the frame entries as a linked list in decreasing sort order + // based on the PC value of the registered entry. + // + // As we store the registrations in increasing order, it would be O(N^2) to + // deregister in that order. + // + // To ensure that we just pop off the first element in the list upon every + // deregistration, walk our list of registrations backwards. + for fde in self.registrations.iter().rev() { + __deregister_frame(*fde as *const _); + } + } + } } |
