Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Supporting backtrace for x86_64-fortanix-unknown-sgx. #57441

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/libstd/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]

Expand Down
4 changes: 3 additions & 1 deletion src/libstd/sys/sgx/abi/mem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
87 changes: 78 additions & 9 deletions src/libstd/sys/sgx/backtrace.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,96 @@
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,
_: F,
_: &BacktraceContext) -> io::Result<bool>
where F: FnMut(&[u8], u32) -> io::Result<()>
{
unsupported()
Ok(false)
}