From e65d4e0e84a876de760cc6564525470808a4b461 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Fri, 3 Jul 2020 17:21:42 +0800 Subject: [PATCH] Kernel: implemented KernelException --- src/runtime/src/comms.rs | 17 +++++++++++++++++ src/runtime/src/eh_artiq.rs | 25 +++++++++++++++++++++++-- src/runtime/src/kernel.rs | 25 +++++++++++++++++++++++++ src/runtime/src/proto_async.rs | 20 ++++++++++++++++++++ 4 files changed, 85 insertions(+), 2 deletions(-) diff --git a/src/runtime/src/comms.rs b/src/runtime/src/comms.rs index a522dd9..ca963ef 100644 --- a/src/runtime/src/comms.rs +++ b/src/runtime/src/comms.rs @@ -189,6 +189,23 @@ async fn handle_run_kernel(stream: &TcpStream, control: &Rc { + write_header(stream, Reply::KernelException).await?; + write_chunk(stream, exception.name.as_ref()).await?; + write_chunk(stream, exception.message.as_ref()).await?; + write_i64(stream, exception.param[0] as i64).await?; + write_i64(stream, exception.param[1] as i64).await?; + write_i64(stream, exception.param[2] as i64).await?; + write_chunk(stream, exception.file.as_ref()).await?; + write_i32(stream, exception.line as i32).await?; + write_i32(stream, exception.column as i32).await?; + write_chunk(stream, exception.function.as_ref()).await?; + write_i32(stream, backtrace.len() as i32).await?; + for &addr in backtrace { + write_i32(stream, addr as i32).await?; + } + break; + } _ => { panic!("unexpected message from core1 while kernel was running: {:?}", reply); } diff --git a/src/runtime/src/eh_artiq.rs b/src/runtime/src/eh_artiq.rs index a81dd3d..2822f26 100644 --- a/src/runtime/src/eh_artiq.rs +++ b/src/runtime/src/eh_artiq.rs @@ -38,6 +38,21 @@ pub struct Exception<'a> { pub param: [i64; 3] } +fn str_err(_: core::str::Utf8Error) -> core::fmt::Error { + core::fmt::Error +} + +impl<'a> core::fmt::Debug for Exception<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "Exception {} from {} in {}:{}:{}, message: {}", + core::str::from_utf8(self.name.as_ref()).map_err(str_err)?, + core::str::from_utf8(self.function.as_ref()).map_err(str_err)?, + core::str::from_utf8(self.file.as_ref()).map_err(str_err)?, + self.line, self.column, + core::str::from_utf8(self.message.as_ref()).map_err(str_err)?) + } +} + const MAX_BACKTRACE_SIZE: usize = 128; #[repr(C)] @@ -189,10 +204,16 @@ pub unsafe extern fn raise(exception: *const Exception) -> ! { let result = uw::_Unwind_RaiseException(&mut INFLIGHT.uw_exception); assert!(result == uw::_URC_END_OF_STACK); - debug!("Result: {:?}", result); INFLIGHT.backtrace_size = 0; - unimplemented!("top level exception handling"); + // read backtrace + let _ = uw::backtrace(|ip| { + if INFLIGHT.backtrace_size < MAX_BACKTRACE_SIZE { + INFLIGHT.backtrace[INFLIGHT.backtrace_size] = ip; + INFLIGHT.backtrace_size += 1; + } + }); + crate::kernel::terminate(INFLIGHT.exception.as_ref().unwrap(), INFLIGHT.backtrace[..INFLIGHT.backtrace_size].as_mut()); } pub unsafe extern fn reraise() -> ! { diff --git a/src/runtime/src/kernel.rs b/src/runtime/src/kernel.rs index 5e8df09..b7006a8 100644 --- a/src/runtime/src/kernel.rs +++ b/src/runtime/src/kernel.rs @@ -19,6 +19,7 @@ pub enum Message { LoadFailed, StartRequest, KernelFinished, + KernelException(&'static eh_artiq::Exception<'static>, &'static [usize]), RpcSend { is_async: bool, data: Arc> }, RpcRecvRequest(*mut ()), RpcRecvReply(Result), @@ -82,6 +83,27 @@ extern fn rpc_send_async(service: u32, tag: &CSlice, data: *const *const ()) rpc_send_common(true, service, tag, data); } +static mut KERNEL_LOAD_ADDR: usize = 0; + +pub fn terminate(exception: &'static eh_artiq::Exception<'static>, backtrace: &'static mut [usize]) -> ! { + let load_addr = unsafe { + KERNEL_LOAD_ADDR + }; + let mut cursor = 0; + // The address in the backtrace is relocated, so we have to convert it back to the address in + // the original python script, and remove those Rust function backtrace. + for i in 0..backtrace.len() { + if backtrace[i] >= load_addr { + backtrace[cursor] = backtrace[i] - load_addr; + cursor += 1; + } + } + + let core1_tx: &mut sync_channel::Sender = unsafe { mem::transmute(KERNEL_CHANNEL_1TO0) }; + core1_tx.send(Message::KernelException(exception, &backtrace[..cursor])); + loop {} +} + unsafe fn attribute_writeback(typeinfo: *const ()) { struct Attr { offset: usize, @@ -299,6 +321,9 @@ pub fn main_core1() { Message::LoadRequest(data) => { match dyld::load(&data, &resolve) { Ok(library) => { + unsafe { + KERNEL_LOAD_ADDR = library.image.as_ptr() as usize; + } let bss_start = library.lookup(b"__bss_start"); let end = library.lookup(b"_end"); if let Some(bss_start) = bss_start { diff --git a/src/runtime/src/proto_async.rs b/src/runtime/src/proto_async.rs index 3e33db7..5188fc3 100644 --- a/src/runtime/src/proto_async.rs +++ b/src/runtime/src/proto_async.rs @@ -104,3 +104,23 @@ pub async fn write_i32(stream: &TcpStream, value: i32) -> Result<()> { value as u8].iter().copied()).await?; Ok(()) } + +pub async fn write_i64(stream: &TcpStream, value: i64) -> Result<()> { + stream.send([ + (value >> 56) as u8, + (value >> 48) as u8, + (value >> 40) as u8, + (value >> 32) as u8, + (value >> 24) as u8, + (value >> 16) as u8, + (value >> 8) as u8, + value as u8].iter().copied()).await?; + Ok(()) +} + +pub async fn write_chunk(stream: &TcpStream, value: &[u8]) -> Result<()> { + write_i32(stream, value.len() as i32).await?; + stream.send(value.iter().copied()).await?; + Ok(()) +} +