blob: b354026e962b84946221bca0471a521c30a45c01 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License..
use crate::ffi::c_void;
use crate::sys::backtrace::Bomb;
use sgx_trts::enclave;
use sgx_unwind as uw;
pub enum Frame {
Raw(*mut uw::_Unwind_Context),
Cloned {
ip: *mut c_void,
sp: *mut c_void,
symbol_address: *mut c_void,
},
}
// With a raw libunwind pointer it should only ever be access in a readonly
// threadsafe fashion, so it's `Sync`. When sending to other threads via `Clone`
// we always switch to a version which doesn't retain interior pointers, so we
// should be `Send` as well.
unsafe impl Send for Frame {}
unsafe impl Sync for Frame {}
impl Frame {
pub fn ip(&self) -> *mut c_void {
let ctx = match *self {
Frame::Raw(ctx) => ctx,
Frame::Cloned { ip, .. } => return ip,
};
unsafe { uw::_Unwind_GetIP(ctx) as *mut c_void }
}
pub fn sp(&self) -> *mut c_void {
match *self {
Frame::Raw(ctx) => unsafe { uw::_Unwind_GetCFA(ctx) as *mut c_void },
Frame::Cloned { sp, .. } => sp,
}
}
pub fn symbol_address(&self) -> *mut c_void {
if let Frame::Cloned { symbol_address, .. } = *self {
return symbol_address;
}
// It seems that on OSX `_Unwind_FindEnclosingFunction` returns a
// pointer to... something that's unclear. It's definitely not always
// the enclosing function for whatever reason. It's not entirely clear
// to me what's going on here, so pessimize this for now and just always
// return the ip.
//
// Note the `skip_inner_frames.rs` test is skipped on OSX due to this
// clause, and if this is fixed that test in theory can be run on OSX!
if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
self.ip()
} else {
unsafe { uw::_Unwind_FindEnclosingFunction(self.ip()) }
}
}
pub fn module_base_address(&self) -> Option<*mut c_void> {
None
}
}
impl Clone for Frame {
fn clone(&self) -> Frame {
Frame::Cloned {
ip: self.ip(),
sp: self.sp(),
symbol_address: self.symbol_address(),
}
}
}
#[inline(always)]
pub unsafe fn trace(mut cb: &mut dyn FnMut(&super::Frame) -> bool) {
uw::_Unwind_Backtrace(trace_fn, &mut cb as *mut _ as *mut _);
extern "C" fn trace_fn(
ctx: *mut uw::_Unwind_Context,
arg: *mut c_void,
) -> uw::_Unwind_Reason_Code {
let cb = unsafe { &mut *(arg as *mut &mut dyn FnMut(&super::Frame) -> bool) };
let cx = super::Frame {
inner: Frame::Raw(ctx),
};
let mut bomb = Bomb::new(true);
let mut keep_going = cb(&cx);
bomb.set(false);
let sym_addr = cx.symbol_address() as usize;
let enclave_entry = enclave::rsgx_get_enclave_entry();
if enclave_entry == sym_addr || enclave_entry == (sym_addr - 0x04) {
//0x04 endbr64
keep_going = false;
}
if keep_going {
uw::_URC_NO_REASON
} else {
uw::_URC_FAILURE
}
}
}