summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-01-12 10:55:07 +0100
committerGitHub <noreply@github.com>2019-01-12 10:55:07 +0100
commit85a7fc8c48f4355e2b9f86dff09e743ab5fbf92f (patch)
treec3e43edec8783c0b78a02dee094ddd010732b07e
parent632d8909a0dbf1c8f2569987b24d36dc013ed5e8 (diff)
parent2e4766c3afcdac9f45edbd73723384b360ee4b68 (diff)
downloadrust-85a7fc8c48f4355e2b9f86dff09e743ab5fbf92f.tar.gz
Rollup merge of #57441 - VardhanThigle:Vardhan/x86_64-fortanix-unknown-sgx-backtrace-support, r=alexcrichton
Supporting backtrace for x86_64-fortanix-unknown-sgx. # Overview Implementing following functions required by `libstd/sys_common` to support `backtrace`: ``` 1. unwind_backtrace 2. trace_fn 3. resolve_symname ``` # Description: The changes here are quite similar to the Cloudabi target `src/libstd/sys/cloudabi/backtrace.rs` The first 2 functions are implemented via calls to libunwind.a that is linked to the `x86_64-fortanix-unknown-sgx` (#56979), we have not implemented functionality needed by `resolve_symname` (or `dladdr`) to reduce SGX TCB. Rather, we print the function address (relative to enclave image base) in `resolve_symname` which can be later translated to correct symbol name (say, via `addr2line`). # Note: For `x86_64-fortanix-unknown-sgx`, the `RUST_BACKTRACE` environment has to be set from within the program running in an enclave. cc: @jethrogb r? @alexcrichton
-rw-r--r--src/libstd/lib.rs2
-rw-r--r--src/libstd/sys/sgx/abi/mem.rs4
-rw-r--r--src/libstd/sys/sgx/backtrace.rs87
3 files changed, 82 insertions, 11 deletions
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 701565191b9..e2200808449 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 09552d5b4af..808f1ce3ff2 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 52d4a63bb63..2b8e1da0579 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<F>(_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<F>(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<F>(_: Frame,
@@ -23,5 +92,5 @@ pub fn foreach_symbol_fileline<F>(_: Frame,
_: &BacktraceContext) -> io::Result<bool>
where F: FnMut(&[u8], u32) -> io::Result<()>
{
- unsupported()
+ Ok(false)
}