forked from M-Labs/artiq
Rust: implement exceptional kernel termination.
This also adjusts the way backtraces are serialized by kloader.
This commit is contained in:
parent
84214ab0d1
commit
226fa723bb
@ -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;
|
||||
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -350,12 +350,39 @@ fn process_kern_message(waiter: Waiter,
|
||||
}
|
||||
|
||||
kern::RunFinished => {
|
||||
try!(kern_acknowledge());
|
||||
|
||||
kernel::stop();
|
||||
session.kernel_state = KernelState::Absent;
|
||||
|
||||
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 {
|
||||
|
@ -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<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)]
|
||||
pub enum Request {
|
||||
Log,
|
||||
@ -67,7 +27,15 @@ pub enum Request {
|
||||
RunKernel,
|
||||
|
||||
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 },
|
||||
FlashWrite { key: String, value: Vec<u8> },
|
||||
@ -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 } => {
|
||||
|
@ -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) {
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user