Kernel: implemented KernelException

core0-buffer
pca006132 2020-07-03 17:21:42 +08:00
parent 6f37128911
commit e65d4e0e84
4 changed files with 85 additions and 2 deletions

View File

@ -189,6 +189,23 @@ async fn handle_run_kernel(stream: &TcpStream, control: &Rc<RefCell<kernel::Cont
write_header(stream, Reply::KernelFinished).await?;
break;
},
kernel::Message::KernelException(exception, backtrace) => {
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);
}

View File

@ -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() -> ! {

View File

@ -19,6 +19,7 @@ pub enum Message {
LoadFailed,
StartRequest,
KernelFinished,
KernelException(&'static eh_artiq::Exception<'static>, &'static [usize]),
RpcSend { is_async: bool, data: Arc<Vec<u8>> },
RpcRecvRequest(*mut ()),
RpcRecvReply(Result<usize, ()>),
@ -82,6 +83,27 @@ extern fn rpc_send_async(service: u32, tag: &CSlice<u8>, 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<Message> = 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 {

View File

@ -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(())
}