From 226fa723bb57c79ca79ee79435d5901ef5922c8a Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 6 Oct 2016 13:42:35 +0000 Subject: [PATCH] Rust: implement exceptional kernel termination. This also adjusts the way backtraces are serialized by kloader. --- artiq/runtime.rs/src/kernel.rs | 1 - artiq/runtime.rs/src/kernel_proto.rs | 13 +--- artiq/runtime.rs/src/session.rs | 37 +++++++++-- artiq/runtime.rs/src/session_proto.rs | 91 ++++++++++++++------------- artiq/runtime/artiq_personality.c | 5 +- artiq/runtime/artiq_personality.h | 7 +-- artiq/runtime/kloader.c | 16 ----- artiq/runtime/kloader.h | 4 -- artiq/runtime/ksupport.c | 15 ++++- artiq/runtime/messages.h | 2 +- artiq/runtime/session.c | 6 +- 11 files changed, 98 insertions(+), 99 deletions(-) diff --git a/artiq/runtime.rs/src/kernel.rs b/artiq/runtime.rs/src/kernel.rs index 050b57ec4..bffc2c12e 100644 --- a/artiq/runtime.rs/src/kernel.rs +++ b/artiq/runtime.rs/src/kernel.rs @@ -3,7 +3,6 @@ use board::csr; use mailbox; const KERNELCPU_EXEC_ADDRESS: usize = 0x42000000; -const KERNELCPU_PAYLOAD_ADDRESS: usize = 0x42020000; const KERNELCPU_LAST_ADDRESS: usize = (0x4fffffff - 1024*1024); const KSUPPORT_HEADER_SIZE: usize = 0x80; diff --git a/artiq/runtime.rs/src/kernel_proto.rs b/artiq/runtime.rs/src/kernel_proto.rs index eb8fb7c2a..b84a93df0 100644 --- a/artiq/runtime.rs/src/kernel_proto.rs +++ b/artiq/runtime.rs/src/kernel_proto.rs @@ -15,8 +15,6 @@ pub struct Exception<'a> { pub param: [u64; 3], } -pub use self::c::BacktraceItem; - #[derive(Debug)] pub enum Message<'a> { LoadRequest(&'a [u8]), @@ -29,7 +27,7 @@ pub enum Message<'a> { RunFinished, RunException { exception: Exception<'a>, - backtrace: &'a [BacktraceItem] + backtrace: &'a [usize] }, WatchdogSetRequest { ms: u64 }, @@ -315,7 +313,7 @@ mod c { pub struct RunException { pub ty: Type, pub exception: *const Exception, - pub backtrace: *const BacktraceItem, + pub backtrace: *const usize, pub backtrace_size: size_t } @@ -417,13 +415,6 @@ mod c { pub param: [u64; 3], } - #[repr(C)] - #[derive(Debug)] - pub struct BacktraceItem { - pub function: usize, - pub offset: usize - } - pub unsafe fn from_c_str_len<'a>(ptr: *const c_char, len: size_t) -> &'a str { str::from_utf8_unchecked(slice::from_raw_parts(ptr as *const u8, len)) } diff --git a/artiq/runtime.rs/src/session.rs b/artiq/runtime.rs/src/session.rs index a2e98d904..2f04926d7 100644 --- a/artiq/runtime.rs/src/session.rs +++ b/artiq/runtime.rs/src/session.rs @@ -350,12 +350,39 @@ fn process_kern_message(waiter: Waiter, } kern::RunFinished => { - try!(kern_acknowledge()); - kernel::stop(); session.kernel_state = KernelState::Absent; - return Ok(true) + match stream { + None => return Ok(true), + Some(ref mut stream) => + host_write(stream, host::Reply::KernelFinished) + } + } + + kern::RunException { exception: ref exn, backtrace } => { + kernel::stop(); + session.kernel_state = KernelState::Absent; + + match stream { + None => { + error!("exception in flash kernel"); + error!("{}: {} {:?}", exn.name, exn.message, exn.param); + error!("at {}:{}:{} in {}", exn.file, exn.line, exn.column, exn.function); + return Ok(true) + }, + Some(ref mut stream) => + host_write(stream, host::Reply::KernelException { + name: exn.name, + message: exn.message, + param: exn.param, + file: exn.file, + line: exn.line, + column: exn.column, + function: exn.function, + backtrace: backtrace + }) + } } request => unexpected!("unexpected request {:?} from kernel CPU", request) @@ -374,9 +401,7 @@ fn host_kernel_worker(waiter: Waiter, } if mailbox::receive() != 0 { - if try!(process_kern_message(waiter, Some(stream), &mut session)) { - try!(host_write(stream, host::Reply::KernelFinished)) - } + try!(process_kern_message(waiter, Some(stream), &mut session)); } if session.kernel_state == KernelState::Running { diff --git a/artiq/runtime.rs/src/session_proto.rs b/artiq/runtime.rs/src/session_proto.rs index fcac0b516..b9f7d92fc 100644 --- a/artiq/runtime.rs/src/session_proto.rs +++ b/artiq/runtime.rs/src/session_proto.rs @@ -15,46 +15,6 @@ fn write_sync(writer: &mut Write) -> io::Result<()> { writer.write_all(&[0x5a; 4]) } -#[derive(Debug)] -pub struct Exception { - name: String, - message: String, - param: [u64; 3], - file: String, - line: u32, - column: u32, - function: String, -} - -impl Exception { - pub fn read_from(reader: &mut Read) -> io::Result { - Ok(Exception { - name: try!(read_string(reader)), - message: try!(read_string(reader)), - param: [try!(read_u64(reader)), - try!(read_u64(reader)), - try!(read_u64(reader))], - file: try!(read_string(reader)), - line: try!(read_u32(reader)), - column: try!(read_u32(reader)), - function: try!(read_string(reader)) - }) - } - - pub fn write_to(&self, writer: &mut Write) -> io::Result<()> { - try!(write_string(writer, &self.name)); - try!(write_string(writer, &self.message)); - try!(write_u64(writer, self.param[0])); - try!(write_u64(writer, self.param[1])); - try!(write_u64(writer, self.param[2])); - try!(write_string(writer, &self.file)); - try!(write_u32(writer, self.line)); - try!(write_u32(writer, self.column)); - try!(write_string(writer, &self.function)); - Ok(()) - } -} - #[derive(Debug)] pub enum Request { Log, @@ -67,7 +27,15 @@ pub enum Request { RunKernel, RpcReply { tag: Vec, data: Vec }, - RpcException(Exception), + RpcException { + name: String, + message: String, + param: [u64; 3], + file: String, + line: u32, + column: u32, + function: String, + }, FlashRead { key: String }, FlashWrite { key: String, value: Vec }, @@ -100,7 +68,17 @@ impl Request { try!(reader.read_exact(&mut data)); Request::RpcReply { tag: tag, data: data } } - 8 => Request::RpcException(try!(Exception::read_from(reader))), + 8 => Request::RpcException { + name: try!(read_string(reader)), + message: try!(read_string(reader)), + param: [try!(read_u64(reader)), + try!(read_u64(reader)), + try!(read_u64(reader))], + file: try!(read_string(reader)), + line: try!(read_u32(reader)), + column: try!(read_u32(reader)), + function: try!(read_string(reader)) + }, 9 => Request::FlashRead { key: try!(read_string(reader)) }, @@ -130,7 +108,16 @@ pub enum Reply<'a> { KernelFinished, KernelStartupFailed, - KernelException(Exception), + KernelException { + name: &'a str, + message: &'a str, + param: [u64; 3], + file: &'a str, + line: u32, + column: u32, + function: &'a str, + backtrace: &'a [usize] + }, RpcRequest { service: u32, data: &'a [u8] }, @@ -179,9 +166,23 @@ impl<'a> Reply<'a> { Reply::KernelStartupFailed => { try!(write_u8(&mut buf, 8)); }, - Reply::KernelException(ref exception) => { + Reply::KernelException { + name, message, param, file, line, column, function, backtrace + } => { try!(write_u8(&mut buf, 9)); - try!(exception.write_to(writer)); + try!(write_string(&mut buf, name)); + try!(write_string(&mut buf, message)); + try!(write_u64(&mut buf, param[0])); + try!(write_u64(&mut buf, param[1])); + try!(write_u64(&mut buf, param[2])); + try!(write_string(&mut buf, file)); + try!(write_u32(&mut buf, line)); + try!(write_u32(&mut buf, column)); + try!(write_string(&mut buf, function)); + try!(write_u32(&mut buf, backtrace.len() as u32)); + for &addr in backtrace { + try!(write_u32(&mut buf, addr as u32)) + } }, Reply::RpcRequest { service, data } => { diff --git a/artiq/runtime/artiq_personality.c b/artiq/runtime/artiq_personality.c index 3d52f3c30..2cc5704b4 100644 --- a/artiq/runtime/artiq_personality.c +++ b/artiq/runtime/artiq_personality.c @@ -233,7 +233,7 @@ struct artiq_raised_exception { struct _Unwind_Exception unwind; struct artiq_exception artiq; int handled; - struct artiq_backtrace_item backtrace[1024]; + uintptr_t backtrace[1024]; size_t backtrace_size; }; @@ -303,8 +303,7 @@ static _Unwind_Reason_Code __artiq_uncaught_exception( uintptr_t pcOffset = pc - funcStart; EH_LOG("===> uncaught (pc=%p+%p)", (void*)funcStart, (void*)pcOffset); - inflight->backtrace[inflight->backtrace_size].function = funcStart; - inflight->backtrace[inflight->backtrace_size].offset = pcOffset; + inflight->backtrace[inflight->backtrace_size] = funcStart + pcOffset; ++inflight->backtrace_size; if(actions & _UA_END_OF_STACK) { diff --git a/artiq/runtime/artiq_personality.h b/artiq/runtime/artiq_personality.h index 0ddf9e88f..b1ed1b8d9 100644 --- a/artiq/runtime/artiq_personality.h +++ b/artiq/runtime/artiq_personality.h @@ -17,11 +17,6 @@ struct artiq_exception { int64_t param[3]; }; -struct artiq_backtrace_item { - intptr_t function; - intptr_t offset; -}; - #ifdef __cplusplus extern "C" { #endif @@ -48,7 +43,7 @@ void __artiq_reraise(void) /* Called by the runtime */ void __artiq_terminate(struct artiq_exception *artiq_exn, - struct artiq_backtrace_item *backtrace, + uintptr_t *backtrace, size_t backtrace_size) __attribute__((noreturn)); diff --git a/artiq/runtime/kloader.c b/artiq/runtime/kloader.c index 3dc98e539..04cd6b90a 100644 --- a/artiq/runtime/kloader.c +++ b/artiq/runtime/kloader.c @@ -58,22 +58,6 @@ void kloader_start_kernel() mailbox_acknowledge(); } -void kloader_filter_backtrace(struct artiq_backtrace_item *backtrace, - size_t *backtrace_size) { - struct artiq_backtrace_item *cursor = backtrace; - - // Remove all backtrace items belonging to ksupport and subtract - // shared object base from the addresses. - for(int i = 0; i < *backtrace_size; i++) { - if(backtrace[i].function > KERNELCPU_PAYLOAD_ADDRESS) { - backtrace[i].function -= KERNELCPU_PAYLOAD_ADDRESS; - *cursor++ = backtrace[i]; - } - } - - *backtrace_size = cursor - backtrace; -} - static int kloader_start_flash_kernel(char *key) { #if (defined CSR_SPIFLASH_BASE && defined CONFIG_SPIFLASH_PAGE_SIZE) diff --git a/artiq/runtime/kloader.h b/artiq/runtime/kloader.h index 2ca8d6a6f..a330c4660 100644 --- a/artiq/runtime/kloader.h +++ b/artiq/runtime/kloader.h @@ -1,16 +1,12 @@ #ifndef __KLOADER_H #define __KLOADER_H -#include "artiq_personality.h" - #define KERNELCPU_EXEC_ADDRESS 0x42000000 #define KERNELCPU_PAYLOAD_ADDRESS 0x42020000 #define KERNELCPU_LAST_ADDRESS (0x4fffffff - 1024*1024) #define KSUPPORT_HEADER_SIZE 0x80 int kloader_load_library(const void *code); -void kloader_filter_backtrace(struct artiq_backtrace_item *backtrace, - size_t *backtrace_size); int kloader_start_startup_kernel(void); int kloader_start_idle_kernel(void); diff --git a/artiq/runtime/ksupport.c b/artiq/runtime/ksupport.c index 7d5b5d21a..ff454440f 100644 --- a/artiq/runtime/ksupport.c +++ b/artiq/runtime/ksupport.c @@ -415,13 +415,26 @@ int main(void) /* called from __artiq_personality */ void __artiq_terminate(struct artiq_exception *artiq_exn, - struct artiq_backtrace_item *backtrace, + uintptr_t *backtrace, size_t backtrace_size) { struct msg_exception msg; now_save(); + uintptr_t *cursor = backtrace; + + // Remove all backtrace items belonging to ksupport and subtract + // shared object base from the addresses. + for(int i = 0; i < backtrace_size; i++) { + if(backtrace[i] > KERNELCPU_PAYLOAD_ADDRESS) { + backtrace[i] -= KERNELCPU_PAYLOAD_ADDRESS; + *cursor++ = backtrace[i]; + } + } + + backtrace_size = cursor - backtrace; + msg.type = MESSAGE_TYPE_EXCEPTION; msg.exception = artiq_exn; msg.backtrace = backtrace; diff --git a/artiq/runtime/messages.h b/artiq/runtime/messages.h index 30b5bba1d..a19190cfd 100644 --- a/artiq/runtime/messages.h +++ b/artiq/runtime/messages.h @@ -56,7 +56,7 @@ struct msg_now_save { struct msg_exception { int type; struct artiq_exception *exception; - struct artiq_backtrace_item *backtrace; + uintptr_t *backtrace; size_t backtrace_size; }; diff --git a/artiq/runtime/session.c b/artiq/runtime/session.c index 1cb361bed..054d808e1 100644 --- a/artiq/runtime/session.c +++ b/artiq/runtime/session.c @@ -973,13 +973,9 @@ static int process_kmsg(struct msg_base *umsg) out_packet_int32(msg->exception->column); out_packet_string(msg->exception->function); - kloader_filter_backtrace(msg->backtrace, - &msg->backtrace_size); - out_packet_int32(msg->backtrace_size); for(int i = 0; i < msg->backtrace_size; i++) { - struct artiq_backtrace_item *item = &msg->backtrace[i]; - out_packet_int32(item->function + item->offset); + out_packet_int32(msg->backtrace[i]); } out_packet_finish();