about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVardhan Thigle <vardhan.thigle@fortanix.com>2019-01-03 10:46:22 +0530
committerVardhan Thigle <vardhan.thigle@fortanix.com>2019-01-08 22:10:55 +0530
commit4166a4e5d0ef32ceb0d67d1f5dba334caf439a0d (patch)
tree525660bdcae9fa71d55ac3874a07cff0374526f1
parent7ad470c0a64ed0801708cee6657e82be097a29ac (diff)
downloadrust-4166a4e5d0ef32ceb0d67d1f5dba334caf439a0d.tar.gz
rust-4166a4e5d0ef32ceb0d67d1f5dba334caf439a0d.zip
Supporting backtrace for x86_64-fortanix-unknown-sgx.
-rw-r--r--src/libstd/lib.rs2
-rw-r--r--src/libstd/sys/sgx/backtrace.rs91
2 files changed, 83 insertions, 10 deletions
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index ccfce672e5f..2f35b58106e 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 52d4a63bb63..7e792300f43 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<F>(_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<F>(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<F>(_: Frame,
@@ -23,5 +96,5 @@ pub fn foreach_symbol_fileline<F>(_: Frame,
                                   _: &BacktraceContext) -> io::Result<bool>
     where F: FnMut(&[u8], u32) -> io::Result<()>
 {
-    unsupported()
+    Ok(false)
 }