Rust: implement exceptional kernel termination.

This also adjusts the way backtraces are serialized by kloader.
This commit is contained in:
whitequark 2016-10-06 13:42:35 +00:00
parent 84214ab0d1
commit 226fa723bb
11 changed files with 98 additions and 99 deletions

View File

@ -3,7 +3,6 @@ use board::csr;
use mailbox; use mailbox;
const KERNELCPU_EXEC_ADDRESS: usize = 0x42000000; const KERNELCPU_EXEC_ADDRESS: usize = 0x42000000;
const KERNELCPU_PAYLOAD_ADDRESS: usize = 0x42020000;
const KERNELCPU_LAST_ADDRESS: usize = (0x4fffffff - 1024*1024); const KERNELCPU_LAST_ADDRESS: usize = (0x4fffffff - 1024*1024);
const KSUPPORT_HEADER_SIZE: usize = 0x80; const KSUPPORT_HEADER_SIZE: usize = 0x80;

View File

@ -15,8 +15,6 @@ pub struct Exception<'a> {
pub param: [u64; 3], pub param: [u64; 3],
} }
pub use self::c::BacktraceItem;
#[derive(Debug)] #[derive(Debug)]
pub enum Message<'a> { pub enum Message<'a> {
LoadRequest(&'a [u8]), LoadRequest(&'a [u8]),
@ -29,7 +27,7 @@ pub enum Message<'a> {
RunFinished, RunFinished,
RunException { RunException {
exception: Exception<'a>, exception: Exception<'a>,
backtrace: &'a [BacktraceItem] backtrace: &'a [usize]
}, },
WatchdogSetRequest { ms: u64 }, WatchdogSetRequest { ms: u64 },
@ -315,7 +313,7 @@ mod c {
pub struct RunException { pub struct RunException {
pub ty: Type, pub ty: Type,
pub exception: *const Exception, pub exception: *const Exception,
pub backtrace: *const BacktraceItem, pub backtrace: *const usize,
pub backtrace_size: size_t pub backtrace_size: size_t
} }
@ -417,13 +415,6 @@ mod c {
pub param: [u64; 3], 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 { 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)) str::from_utf8_unchecked(slice::from_raw_parts(ptr as *const u8, len))
} }

View File

@ -350,12 +350,39 @@ fn process_kern_message(waiter: Waiter,
} }
kern::RunFinished => { kern::RunFinished => {
try!(kern_acknowledge());
kernel::stop(); kernel::stop();
session.kernel_state = KernelState::Absent; 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) request => unexpected!("unexpected request {:?} from kernel CPU", request)
@ -374,9 +401,7 @@ fn host_kernel_worker(waiter: Waiter,
} }
if mailbox::receive() != 0 { if mailbox::receive() != 0 {
if try!(process_kern_message(waiter, Some(stream), &mut session)) { try!(process_kern_message(waiter, Some(stream), &mut session));
try!(host_write(stream, host::Reply::KernelFinished))
}
} }
if session.kernel_state == KernelState::Running { if session.kernel_state == KernelState::Running {

View File

@ -15,46 +15,6 @@ fn write_sync(writer: &mut Write) -> io::Result<()> {
writer.write_all(&[0x5a; 4]) 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<Exception> {
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)] #[derive(Debug)]
pub enum Request { pub enum Request {
Log, Log,
@ -67,7 +27,15 @@ pub enum Request {
RunKernel, RunKernel,
RpcReply { tag: Vec<u8>, data: Vec<u8> }, RpcReply { tag: Vec<u8>, data: Vec<u8> },
RpcException(Exception), RpcException {
name: String,
message: String,
param: [u64; 3],
file: String,
line: u32,
column: u32,
function: String,
},
FlashRead { key: String }, FlashRead { key: String },
FlashWrite { key: String, value: Vec<u8> }, FlashWrite { key: String, value: Vec<u8> },
@ -100,7 +68,17 @@ impl Request {
try!(reader.read_exact(&mut data)); try!(reader.read_exact(&mut data));
Request::RpcReply { tag: tag, data: 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 { 9 => Request::FlashRead {
key: try!(read_string(reader)) key: try!(read_string(reader))
}, },
@ -130,7 +108,16 @@ pub enum Reply<'a> {
KernelFinished, KernelFinished,
KernelStartupFailed, 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] }, RpcRequest { service: u32, data: &'a [u8] },
@ -179,9 +166,23 @@ impl<'a> Reply<'a> {
Reply::KernelStartupFailed => { Reply::KernelStartupFailed => {
try!(write_u8(&mut buf, 8)); 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!(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 } => { Reply::RpcRequest { service, data } => {

View File

@ -233,7 +233,7 @@ struct artiq_raised_exception {
struct _Unwind_Exception unwind; struct _Unwind_Exception unwind;
struct artiq_exception artiq; struct artiq_exception artiq;
int handled; int handled;
struct artiq_backtrace_item backtrace[1024]; uintptr_t backtrace[1024];
size_t backtrace_size; size_t backtrace_size;
}; };
@ -303,8 +303,7 @@ static _Unwind_Reason_Code __artiq_uncaught_exception(
uintptr_t pcOffset = pc - funcStart; uintptr_t pcOffset = pc - funcStart;
EH_LOG("===> uncaught (pc=%p+%p)", (void*)funcStart, (void*)pcOffset); EH_LOG("===> uncaught (pc=%p+%p)", (void*)funcStart, (void*)pcOffset);
inflight->backtrace[inflight->backtrace_size].function = funcStart; inflight->backtrace[inflight->backtrace_size] = funcStart + pcOffset;
inflight->backtrace[inflight->backtrace_size].offset = pcOffset;
++inflight->backtrace_size; ++inflight->backtrace_size;
if(actions & _UA_END_OF_STACK) { if(actions & _UA_END_OF_STACK) {

View File

@ -17,11 +17,6 @@ struct artiq_exception {
int64_t param[3]; int64_t param[3];
}; };
struct artiq_backtrace_item {
intptr_t function;
intptr_t offset;
};
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -48,7 +43,7 @@ void __artiq_reraise(void)
/* Called by the runtime */ /* Called by the runtime */
void __artiq_terminate(struct artiq_exception *artiq_exn, void __artiq_terminate(struct artiq_exception *artiq_exn,
struct artiq_backtrace_item *backtrace, uintptr_t *backtrace,
size_t backtrace_size) size_t backtrace_size)
__attribute__((noreturn)); __attribute__((noreturn));

View File

@ -58,22 +58,6 @@ void kloader_start_kernel()
mailbox_acknowledge(); 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) static int kloader_start_flash_kernel(char *key)
{ {
#if (defined CSR_SPIFLASH_BASE && defined CONFIG_SPIFLASH_PAGE_SIZE) #if (defined CSR_SPIFLASH_BASE && defined CONFIG_SPIFLASH_PAGE_SIZE)

View File

@ -1,16 +1,12 @@
#ifndef __KLOADER_H #ifndef __KLOADER_H
#define __KLOADER_H #define __KLOADER_H
#include "artiq_personality.h"
#define KERNELCPU_EXEC_ADDRESS 0x42000000 #define KERNELCPU_EXEC_ADDRESS 0x42000000
#define KERNELCPU_PAYLOAD_ADDRESS 0x42020000 #define KERNELCPU_PAYLOAD_ADDRESS 0x42020000
#define KERNELCPU_LAST_ADDRESS (0x4fffffff - 1024*1024) #define KERNELCPU_LAST_ADDRESS (0x4fffffff - 1024*1024)
#define KSUPPORT_HEADER_SIZE 0x80 #define KSUPPORT_HEADER_SIZE 0x80
int kloader_load_library(const void *code); 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_startup_kernel(void);
int kloader_start_idle_kernel(void); int kloader_start_idle_kernel(void);

View File

@ -415,13 +415,26 @@ int main(void)
/* called from __artiq_personality */ /* called from __artiq_personality */
void __artiq_terminate(struct artiq_exception *artiq_exn, void __artiq_terminate(struct artiq_exception *artiq_exn,
struct artiq_backtrace_item *backtrace, uintptr_t *backtrace,
size_t backtrace_size) size_t backtrace_size)
{ {
struct msg_exception msg; struct msg_exception msg;
now_save(); 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.type = MESSAGE_TYPE_EXCEPTION;
msg.exception = artiq_exn; msg.exception = artiq_exn;
msg.backtrace = backtrace; msg.backtrace = backtrace;

View File

@ -56,7 +56,7 @@ struct msg_now_save {
struct msg_exception { struct msg_exception {
int type; int type;
struct artiq_exception *exception; struct artiq_exception *exception;
struct artiq_backtrace_item *backtrace; uintptr_t *backtrace;
size_t backtrace_size; size_t backtrace_size;
}; };

View File

@ -973,13 +973,9 @@ static int process_kmsg(struct msg_base *umsg)
out_packet_int32(msg->exception->column); out_packet_int32(msg->exception->column);
out_packet_string(msg->exception->function); out_packet_string(msg->exception->function);
kloader_filter_backtrace(msg->backtrace,
&msg->backtrace_size);
out_packet_int32(msg->backtrace_size); out_packet_int32(msg->backtrace_size);
for(int i = 0; i < msg->backtrace_size; i++) { for(int i = 0; i < msg->backtrace_size; i++) {
struct artiq_backtrace_item *item = &msg->backtrace[i]; out_packet_int32(msg->backtrace[i]);
out_packet_int32(item->function + item->offset);
} }
out_packet_finish(); out_packet_finish();