|
1 | 1 | use io;
|
2 |
| -use sys::unsupported; |
| 2 | +use error::Error; |
| 3 | +use libc; |
3 | 4 | use sys_common::backtrace::Frame;
|
| 5 | +use unwind as uw; |
| 6 | +use sys::sgx::abi::mem::image_base; |
4 | 7 |
|
5 | 8 | pub struct BacktraceContext;
|
6 | 9 |
|
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 |
11 | 77 | }
|
12 | 78 |
|
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, |
15 | 83 | _: &BacktraceContext) -> io::Result<()>
|
16 | 84 | where F: FnOnce(Option<&str>) -> io::Result<()>
|
17 | 85 | {
|
18 |
| - unsupported() |
| 86 | + callback(Some(&format!("0x{:x}", |
| 87 | + (frame.symbol_addr.wrapping_offset_from(image_base() as _))))) |
19 | 88 | }
|
20 | 89 |
|
21 | 90 | pub fn foreach_symbol_fileline<F>(_: Frame,
|
22 | 91 | _: F,
|
23 | 92 | _: &BacktraceContext) -> io::Result<bool>
|
24 | 93 | where F: FnMut(&[u8], u32) -> io::Result<()>
|
25 | 94 | {
|
26 |
| - unsupported() |
| 95 | + Ok(false) |
27 | 96 | }
|
0 commit comments