Skip to content

Commit 85a7fc8

Browse files
authored
Rollup merge of rust-lang#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` (rust-lang#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
2 parents 632d890 + 2e4766c commit 85a7fc8

File tree

3 files changed

+82
-11
lines changed

3 files changed

+82
-11
lines changed

src/libstd/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@
305305
#![feature(maybe_uninit)]
306306
#![cfg_attr(all(target_vendor = "fortanix", target_env = "sgx"),
307307
feature(global_asm, range_contains, slice_index_methods,
308-
decl_macro, coerce_unsized, sgx_platform))]
308+
decl_macro, coerce_unsized, sgx_platform, ptr_wrapping_offset_from))]
309309

310310
#![default_lib_allocator]
311311

src/libstd/sys/sgx/abi/mem.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ extern {
1717
// Do not remove inline: will result in relocation failure
1818
// For the same reason we use inline ASM here instead of an extern static to
1919
// locate the base
20+
/// Returns address at which current enclave is loaded.
2021
#[inline(always)]
21-
fn image_base() -> u64 {
22+
#[unstable(feature = "sgx_platform", issue = "56975")]
23+
pub fn image_base() -> u64 {
2224
let base;
2325
unsafe { asm!("lea IMAGE_BASE(%rip),$0":"=r"(base)) };
2426
base

src/libstd/sys/sgx/backtrace.rs

+78-9
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,96 @@
11
use io;
2-
use sys::unsupported;
2+
use error::Error;
3+
use libc;
34
use sys_common::backtrace::Frame;
5+
use unwind as uw;
6+
use sys::sgx::abi::mem::image_base;
47

58
pub struct BacktraceContext;
69

7-
pub fn unwind_backtrace(_frames: &mut [Frame])
8-
-> io::Result<(usize, BacktraceContext)>
9-
{
10-
unsupported()
10+
struct Context<'a> {
11+
idx: usize,
12+
frames: &'a mut [Frame],
13+
}
14+
15+
#[derive(Debug)]
16+
struct UnwindError(uw::_Unwind_Reason_Code);
17+
18+
impl Error for UnwindError {
19+
fn description(&self) -> &'static str {
20+
"unexpected return value while unwinding"
21+
}
22+
}
23+
24+
impl ::fmt::Display for UnwindError {
25+
fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
26+
write!(f, "{}: {:?}", self.description(), self.0)
27+
}
28+
}
29+
30+
#[inline(never)] // this function call can be skipped it when tracing.
31+
pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> {
32+
let mut cx = Context { idx: 0, frames };
33+
let result_unwind =
34+
unsafe { uw::_Unwind_Backtrace(trace_fn, &mut cx as *mut Context as *mut libc::c_void) };
35+
// See libunwind:src/unwind/Backtrace.c for the return values.
36+
// No, there is no doc.
37+
let res = match result_unwind {
38+
// These return codes seem to be benign and need to be ignored for backtraces
39+
// to show up properly on all tested platforms.
40+
uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => {
41+
Ok((cx.idx, BacktraceContext))
42+
}
43+
_ => Err(io::Error::new(
44+
io::ErrorKind::Other,
45+
UnwindError(result_unwind),
46+
)),
47+
};
48+
res
49+
}
50+
51+
extern "C" fn trace_fn(
52+
ctx: *mut uw::_Unwind_Context,
53+
arg: *mut libc::c_void,
54+
) -> uw::_Unwind_Reason_Code {
55+
let cx = unsafe { &mut *(arg as *mut Context) };
56+
if cx.idx >= cx.frames.len() {
57+
return uw::_URC_NORMAL_STOP;
58+
}
59+
60+
let mut ip_before_insn = 0;
61+
let mut ip = unsafe { uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void };
62+
if !ip.is_null() && ip_before_insn == 0 {
63+
// this is a non-signaling frame, so `ip` refers to the address
64+
// after the calling instruction. account for that.
65+
ip = (ip as usize - 1) as *mut _;
66+
}
67+
68+
let symaddr = unsafe { uw::_Unwind_FindEnclosingFunction(ip) };
69+
cx.frames[cx.idx] = Frame {
70+
symbol_addr: symaddr as *mut u8,
71+
exact_position: ip as *mut u8,
72+
inline_context: 0,
73+
};
74+
cx.idx += 1;
75+
76+
uw::_URC_NO_REASON
1177
}
1278

13-
pub fn resolve_symname<F>(_frame: Frame,
14-
_callback: F,
79+
// To reduce TCB size in Sgx enclave, we do not want to implement resolve_symname functionality.
80+
// Rather, we print the offset of the address here, which could be later mapped to correct function.
81+
pub fn resolve_symname<F>(frame: Frame,
82+
callback: F,
1583
_: &BacktraceContext) -> io::Result<()>
1684
where F: FnOnce(Option<&str>) -> io::Result<()>
1785
{
18-
unsupported()
86+
callback(Some(&format!("0x{:x}",
87+
(frame.symbol_addr.wrapping_offset_from(image_base() as _)))))
1988
}
2089

2190
pub fn foreach_symbol_fileline<F>(_: Frame,
2291
_: F,
2392
_: &BacktraceContext) -> io::Result<bool>
2493
where F: FnMut(&[u8], u32) -> io::Result<()>
2594
{
26-
unsupported()
95+
Ok(false)
2796
}

0 commit comments

Comments
 (0)