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/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 52d4a63bb6384..2b8e1da05791d 100644 --- a/src/libstd/sys/sgx/backtrace.rs +++ b/src/libstd/sys/sgx/backtrace.rs @@ -1,21 +1,90 @@ use io; -use sys::unsupported; +use error::Error; +use libc; use sys_common::backtrace::Frame; +use unwind as uw; +use sys::sgx::abi::mem::image_base; 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 +} + +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 } -pub fn resolve_symname(_frame: Frame, - _callback: F, +// 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}", + (frame.symbol_addr.wrapping_offset_from(image_base() as _))))) } pub fn foreach_symbol_fileline(_: Frame, @@ -23,5 +92,5 @@ pub fn foreach_symbol_fileline(_: Frame, _: &BacktraceContext) -> io::Result where F: FnMut(&[u8], u32) -> io::Result<()> { - unsupported() + Ok(false) }