From 4166a4e5d0ef32ceb0d67d1f5dba334caf439a0d Mon Sep 17 00:00:00 2001 From: Vardhan Thigle Date: Thu, 3 Jan 2019 10:46:22 +0530 Subject: [PATCH 1/2] Supporting backtrace for x86_64-fortanix-unknown-sgx. --- src/libstd/lib.rs | 2 +- src/libstd/sys/sgx/backtrace.rs | 91 +++++++++++++++++++++++++++++---- 2 files changed, 83 insertions(+), 10 deletions(-) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index ccfce672e5f9e..2f35b58106eab 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -305,7 +305,7 @@ #![feature(maybe_uninit)] #![cfg_attr(all(target_vendor = "fortanix", target_env = "sgx"), feature(global_asm, range_contains, slice_index_methods, - decl_macro, coerce_unsized, sgx_platform))] + decl_macro, coerce_unsized, sgx_platform, ptr_wrapping_offset_from))] #![default_lib_allocator] diff --git a/src/libstd/sys/sgx/backtrace.rs b/src/libstd/sys/sgx/backtrace.rs index 52d4a63bb6384..7e792300f434c 100644 --- a/src/libstd/sys/sgx/backtrace.rs +++ b/src/libstd/sys/sgx/backtrace.rs @@ -1,21 +1,94 @@ use io; -use sys::unsupported; +use error::Error; +use libc; use sys_common::backtrace::Frame; +use unwind as uw; pub struct BacktraceContext; -pub fn unwind_backtrace(_frames: &mut [Frame]) - -> io::Result<(usize, BacktraceContext)> -{ - unsupported() +struct Context<'a> { + idx: usize, + frames: &'a mut [Frame], +} + +#[derive(Debug)] +struct UnwindError(uw::_Unwind_Reason_Code); + +impl Error for UnwindError { + fn description(&self) -> &'static str { + "unexpected return value while unwinding" + } +} + +impl ::fmt::Display for UnwindError { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + write!(f, "{}: {:?}", self.description(), self.0) + } +} + +#[inline(never)] // this function call can be skipped it when tracing. +pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> { + let mut cx = Context { idx: 0, frames }; + let result_unwind = + unsafe { uw::_Unwind_Backtrace(trace_fn, &mut cx as *mut Context as *mut libc::c_void) }; + // See libunwind:src/unwind/Backtrace.c for the return values. + // No, there is no doc. + let res = match result_unwind { + // These return codes seem to be benign and need to be ignored for backtraces + // to show up properly on all tested platforms. + uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => { + Ok((cx.idx, BacktraceContext)) + } + _ => Err(io::Error::new( + io::ErrorKind::Other, + UnwindError(result_unwind), + )), + }; + res } -pub fn resolve_symname(_frame: Frame, - _callback: F, +extern "C" fn trace_fn( + ctx: *mut uw::_Unwind_Context, + arg: *mut libc::c_void, +) -> uw::_Unwind_Reason_Code { + let cx = unsafe { &mut *(arg as *mut Context) }; + if cx.idx >= cx.frames.len() { + return uw::_URC_NORMAL_STOP; + } + + let mut ip_before_insn = 0; + let mut ip = unsafe { uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void }; + if !ip.is_null() && ip_before_insn == 0 { + // this is a non-signaling frame, so `ip` refers to the address + // after the calling instruction. account for that. + ip = (ip as usize - 1) as *mut _; + } + + let symaddr = unsafe { uw::_Unwind_FindEnclosingFunction(ip) }; + cx.frames[cx.idx] = Frame { + symbol_addr: symaddr as *mut u8, + exact_position: ip as *mut u8, + inline_context: 0, + }; + cx.idx += 1; + + uw::_URC_NO_REASON +} + +extern { + static IMAGE_BASE: u8; +} + + +// To reduce TCB size in Sgx enclave, we do not want to implement resolve_symname functionality. +// Rather, we print the offset of the address here, which could be later mapped to correct function. +pub fn resolve_symname(frame: Frame, + callback: F, _: &BacktraceContext) -> io::Result<()> where F: FnOnce(Option<&str>) -> io::Result<()> { - unsupported() + callback(Some(&format!("0x{:x}", + (unsafe {frame.symbol_addr.wrapping_offset_from(&IMAGE_BASE)})))) } pub fn foreach_symbol_fileline(_: Frame, @@ -23,5 +96,5 @@ pub fn foreach_symbol_fileline(_: Frame, _: &BacktraceContext) -> io::Result where F: FnMut(&[u8], u32) -> io::Result<()> { - unsupported() + Ok(false) } From 2e4766c3afcdac9f45edbd73723384b360ee4b68 Mon Sep 17 00:00:00 2001 From: Vardhan Thigle Date: Wed, 9 Jan 2019 17:20:37 +0530 Subject: [PATCH 2/2] Exposing enclave image-base to the enclave application image-base could be used by crates like backtrace to providing to make symbol resolution easier. --- src/libstd/sys/sgx/abi/mem.rs | 4 +++- src/libstd/sys/sgx/backtrace.rs | 8 ++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/libstd/sys/sgx/abi/mem.rs b/src/libstd/sys/sgx/abi/mem.rs index 09552d5b4af29..808f1ce3ff2c7 100644 --- a/src/libstd/sys/sgx/abi/mem.rs +++ b/src/libstd/sys/sgx/abi/mem.rs @@ -17,8 +17,10 @@ extern { // Do not remove inline: will result in relocation failure // For the same reason we use inline ASM here instead of an extern static to // locate the base +/// Returns address at which current enclave is loaded. #[inline(always)] -fn image_base() -> u64 { +#[unstable(feature = "sgx_platform", issue = "56975")] +pub fn image_base() -> u64 { let base; unsafe { asm!("lea IMAGE_BASE(%rip),$0":"=r"(base)) }; base diff --git a/src/libstd/sys/sgx/backtrace.rs b/src/libstd/sys/sgx/backtrace.rs index 7e792300f434c..2b8e1da05791d 100644 --- a/src/libstd/sys/sgx/backtrace.rs +++ b/src/libstd/sys/sgx/backtrace.rs @@ -3,6 +3,7 @@ use error::Error; use libc; use sys_common::backtrace::Frame; use unwind as uw; +use sys::sgx::abi::mem::image_base; pub struct BacktraceContext; @@ -75,11 +76,6 @@ extern "C" fn trace_fn( uw::_URC_NO_REASON } -extern { - static IMAGE_BASE: u8; -} - - // To reduce TCB size in Sgx enclave, we do not want to implement resolve_symname functionality. // Rather, we print the offset of the address here, which could be later mapped to correct function. pub fn resolve_symname(frame: Frame, @@ -88,7 +84,7 @@ pub fn resolve_symname(frame: Frame, where F: FnOnce(Option<&str>) -> io::Result<()> { callback(Some(&format!("0x{:x}", - (unsafe {frame.symbol_addr.wrapping_offset_from(&IMAGE_BASE)})))) + (frame.symbol_addr.wrapping_offset_from(image_base() as _))))) } pub fn foreach_symbol_fileline(_: Frame,