use libc;
use std::sync::atomic::{AtomicBool,Ordering};
use std::sync::{RwLock,RwLockReadGuard};
use std::io::{stdout,stdin,Write,Error as IoError,ErrorKind as IoErrorKind};
use sgxs::loader::{Tcs,Address};
use sgx_isa::Enclu;
lazy_static! {
static ref SIGNAL_HANDLER: RwLock<Option<SignalHandler>> = RwLock::new(None);
}
struct SignalHandler {
old_handler: libc::sighandler_t,
in_segv: AtomicBool,
buf: [u64;512],
tcs: Address,
}
extern "C" fn segv_handler() -> ! {
let lock=SIGNAL_HANDLER.read().unwrap();
let handler=lock.as_ref().unwrap();
println!("Segmentation fault. Debug mode activated.");
if handler.in_segv.swap(true,Ordering::Relaxed) {
panic!("Double segfault!")
}
loop {
let mut instr=String::new();
println!("TCS={:x}, read addr?",u64::from(handler.tcs));
print!("0x");
stdout().flush().unwrap();
stdin().read_line(&mut instr).unwrap();
instr.pop();
let inaddr=u64::from_str_radix(&instr,16).unwrap();
let result: u32;
unsafe {
asm!("
lea 1f(%rip),%rcx
1:
enclu
" : "={eax}"(result)
: "{eax}"(Enclu::EEnter), "{rbx}"(u64::from(handler.tcs)), "{rdi}"(handler.buf.as_ptr()), "{rsi}"(inaddr)
: "rcx", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "memory"
: "volatile"
)};
if result!=(Enclu::EExit as u32) {
panic!("Invalid return value in EAX! eax={}",result);
}
for (n,vals) in handler.buf.chunks(4).enumerate() {
println!("{:03x} {:016x} {:016x} {:016x} {:016x}",n*4*8,vals[0],vals[1],vals[2],vals[3]);
}
}
}
pub struct InstalledSignalHandler {
lock: Option<RwLockReadGuard<'static,Option<SignalHandler>>>,
}
impl Drop for InstalledSignalHandler {
fn drop(&mut self) {
drop(self.lock.take().unwrap());
let mut lock=SIGNAL_HANDLER.write().unwrap();
let handler=lock.take().unwrap();
unsafe{libc::signal(libc::SIGSEGV,handler.old_handler)};
}
}
pub fn install_segv_signal_handler(tcs: &mut Tcs) -> Result<InstalledSignalHandler,IoError> {
let mut lock=SIGNAL_HANDLER.write().unwrap();
if lock.is_some() {
return Err(IoError::new(IoErrorKind::AlreadyExists,"A signal handler is already installed"));
}
match unsafe{libc::signal(libc::SIGSEGV,segv_handler as *const () as libc::sighandler_t)} {
libc::SIG_ERR => Err(IoError::last_os_error()),
h @ _ => {
*lock=Some(SignalHandler{
old_handler:h,
in_segv:AtomicBool::new(false),
buf:[0;512],
tcs:unsafe{tcs.address()}, });
drop(lock);
Ok(InstalledSignalHandler{lock:Some(SIGNAL_HANDLER.read().unwrap())})
},
}
}