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;
|
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;
|
||||||
|
|
||||||
|
@ -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))
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
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)
|
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 {
|
||||||
|
@ -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 } => {
|
||||||
|
@ -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) {
|
||||||
|
@ -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));
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
Loading…
Reference in New Issue
Block a user