mirror of https://github.com/m-labs/artiq.git
parent
fb1dfcf372
commit
b91822ffe6
|
@ -17,6 +17,11 @@ dependencies = [
|
|||
name = "backtrace_artiq"
|
||||
version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "board"
|
||||
version = "0.0.0"
|
||||
|
@ -37,6 +42,11 @@ name = "byteorder"
|
|||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "compiler_builtins"
|
||||
version = "0.1.0"
|
||||
|
@ -65,10 +75,17 @@ dependencies = [
|
|||
name = "dyld"
|
||||
version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "eh"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fringe"
|
||||
version = "1.1.0"
|
||||
source = "git+https://github.com/m-labs/libfringe?rev=bd23494#bd2349467157969324ca7da5d2ae033c7ffac0c0"
|
||||
source = "git+https://github.com/m-labs/libfringe?rev=b8a6d8f#b8a6d8f68df0edaa3d67d9f3b7b62af9d3bb64a5"
|
||||
dependencies = [
|
||||
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
@ -98,6 +115,7 @@ dependencies = [
|
|||
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dyld 0.0.0",
|
||||
"eh 0.0.0",
|
||||
"proto 0.0.0",
|
||||
"std_artiq 0.0.0",
|
||||
]
|
||||
|
@ -112,23 +130,31 @@ name = "log"
|
|||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log_buffer"
|
||||
version = "1.2.0"
|
||||
source = "git+https://github.com/whitequark/rust-log_buffer?rev=rust-1.25#ff84e565d9954d5864d60aec12b9e1381505d72a"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "logger_artiq"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"board 0.0.0",
|
||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log_buffer 1.2.0 (git+https://github.com/whitequark/rust-log_buffer?rev=rust-1.25)",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log_buffer 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "managed"
|
||||
version = "0.5.0"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
@ -138,7 +164,7 @@ dependencies = [
|
|||
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dyld 0.0.0",
|
||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"std_artiq 0.0.0",
|
||||
]
|
||||
|
||||
|
@ -152,14 +178,14 @@ dependencies = [
|
|||
"board 0.0.0",
|
||||
"build_artiq 0.0.0",
|
||||
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins?rev=631b568)",
|
||||
"cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"drtioaux 0.0.0",
|
||||
"fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=bd23494)",
|
||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=b8a6d8f)",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"logger_artiq 0.0.0",
|
||||
"managed 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proto 0.0.0",
|
||||
"smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=181083f)",
|
||||
"smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=2139686)",
|
||||
"std_artiq 0.0.0",
|
||||
]
|
||||
|
||||
|
@ -194,11 +220,12 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "smoltcp"
|
||||
version = "0.4.0"
|
||||
source = "git+https://github.com/m-labs/smoltcp?rev=181083f#181083f18c977b8a0463a67e360e4db20594fa21"
|
||||
source = "git+https://github.com/m-labs/smoltcp?rev=2139686#21396867114d267da06f19cc54cc4a1883b900a5"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"managed 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"managed 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -226,19 +253,22 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||
"checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23"
|
||||
"checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3"
|
||||
"checksum compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins?rev=631b568)" = "<none>"
|
||||
"checksum cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0f8cb7306107e4b10e64994de6d3274bd08996a7c1322a27b86482392f96be0a"
|
||||
"checksum fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=bd23494)" = "<none>"
|
||||
"checksum fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=b8a6d8f)" = "<none>"
|
||||
"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)" = "36fbc8a8929c632868295d0178dd8f63fc423fd7537ad0738372bd010b3ac9b0"
|
||||
"checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b"
|
||||
"checksum log_buffer 1.2.0 (git+https://github.com/whitequark/rust-log_buffer?rev=rust-1.25)" = "<none>"
|
||||
"checksum managed 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "786bd3519bdfb0e1a57146a74b7584555dd6c4f1b6e1137c70e177d60dde8186"
|
||||
"checksum log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fcce5fa49cc693c312001daf1d13411c4a5283796bac1084299ea3e567113f"
|
||||
"checksum log_buffer 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f033173c9486b7fe97a79c895c0a3483ae395ab6744c985d10078950e2492419"
|
||||
"checksum managed 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba6713e624266d7600e9feae51b1926c6a6a6bebb18ec5a8e11a5f1d5661baba"
|
||||
"checksum rustc-cfg 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56a596b5718bf5e059d59a30af12f7f462a152de147aa462b70892849ee18704"
|
||||
"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7"
|
||||
"checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=181083f)" = "<none>"
|
||||
"checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=2139686)" = "<none>"
|
||||
"checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
|
|
|
@ -3,4 +3,5 @@ members = ["runtime", "ksupport", "satman"]
|
|||
|
||||
[profile.dev]
|
||||
incremental = false # incompatible with LTO
|
||||
lto = true
|
||||
debug = 2
|
||||
|
|
|
@ -17,6 +17,7 @@ byteorder = { version = "1.0", default-features = false }
|
|||
cslice = { version = "0.3" }
|
||||
alloc_stub = { path = "../liballoc_stub" }
|
||||
std_artiq = { path = "../libstd_artiq" }
|
||||
eh = { path = "../libeh" }
|
||||
dyld = { path = "../libdyld" }
|
||||
board = { path = "../libboard" }
|
||||
proto = { path = "../libproto" }
|
||||
|
|
|
@ -9,6 +9,7 @@ CFLAGS += \
|
|||
LDFLAGS += --eh-frame-hdr \
|
||||
-L../libcompiler-rt \
|
||||
-L../libbase \
|
||||
-L../libprintf \
|
||||
-L../libm \
|
||||
-L../libunwind
|
||||
|
||||
|
@ -22,7 +23,7 @@ $(RUSTOUT)/libksupport.a:
|
|||
|
||||
ksupport.elf: $(RUSTOUT)/libksupport.a glue.o
|
||||
$(link) -T $(KSUPPORT_DIRECTORY)/ksupport.ld \
|
||||
-lunwind-elf -lcompiler-rt -lbase -lm
|
||||
-lunwind-elf -lcompiler-rt -lprintf-float -lm
|
||||
|
||||
%.o: $(KSUPPORT_DIRECTORY)/%.c
|
||||
$(compile)
|
||||
|
|
|
@ -75,9 +75,9 @@ static mut API: &'static [(&'static str, *const ())] = &[
|
|||
|
||||
/* exceptions */
|
||||
api!(_Unwind_Resume = ::unwind::_Unwind_Resume),
|
||||
api!(__artiq_personality = ::eh::personality),
|
||||
api!(__artiq_raise = ::eh::raise),
|
||||
api!(__artiq_reraise = ::eh::reraise),
|
||||
api!(__artiq_personality = ::eh_artiq::personality),
|
||||
api!(__artiq_raise = ::eh_artiq::raise),
|
||||
api!(__artiq_reraise = ::eh_artiq::reraise),
|
||||
|
||||
/* proxified syscalls */
|
||||
api!(core_log),
|
||||
|
|
|
@ -1,474 +0,0 @@
|
|||
// Portions of the code in this file are derived from code by:
|
||||
//
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
#![allow(non_upper_case_globals, non_camel_case_types, dead_code)]
|
||||
|
||||
use core::{ptr, mem};
|
||||
use cslice::CSlice;
|
||||
use unwind as uw;
|
||||
use libc::{c_int, c_void};
|
||||
|
||||
type _Unwind_Stop_Fn = extern "C" fn(version: c_int,
|
||||
actions: uw::_Unwind_Action,
|
||||
exception_class: uw::_Unwind_Exception_Class,
|
||||
exception_object: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context,
|
||||
stop_parameter: *mut c_void)
|
||||
-> uw::_Unwind_Reason_Code;
|
||||
extern {
|
||||
fn _Unwind_ForcedUnwind(exception: *mut uw::_Unwind_Exception,
|
||||
stop_fn: _Unwind_Stop_Fn,
|
||||
stop_parameter: *mut c_void) -> uw::_Unwind_Reason_Code;
|
||||
}
|
||||
|
||||
const DW_EH_PE_omit: u8 = 0xFF;
|
||||
const DW_EH_PE_absptr: u8 = 0x00;
|
||||
|
||||
const DW_EH_PE_uleb128: u8 = 0x01;
|
||||
const DW_EH_PE_udata2: u8 = 0x02;
|
||||
const DW_EH_PE_udata4: u8 = 0x03;
|
||||
const DW_EH_PE_udata8: u8 = 0x04;
|
||||
const DW_EH_PE_sleb128: u8 = 0x09;
|
||||
const DW_EH_PE_sdata2: u8 = 0x0A;
|
||||
const DW_EH_PE_sdata4: u8 = 0x0B;
|
||||
const DW_EH_PE_sdata8: u8 = 0x0C;
|
||||
|
||||
const DW_EH_PE_pcrel: u8 = 0x10;
|
||||
const DW_EH_PE_textrel: u8 = 0x20;
|
||||
const DW_EH_PE_datarel: u8 = 0x30;
|
||||
const DW_EH_PE_funcrel: u8 = 0x40;
|
||||
const DW_EH_PE_aligned: u8 = 0x50;
|
||||
|
||||
const DW_EH_PE_indirect: u8 = 0x80;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct DwarfReader {
|
||||
pub ptr: *const u8,
|
||||
}
|
||||
|
||||
#[repr(C,packed)]
|
||||
#[derive(Clone, Copy)]
|
||||
struct Unaligned<T>(T);
|
||||
|
||||
// This contortion is required due to https://github.com/rust-lang/rust/issues/27060.
|
||||
impl<T> Unaligned<T> {
|
||||
fn get(self) -> T { self.0 }
|
||||
}
|
||||
|
||||
impl DwarfReader {
|
||||
fn new(ptr: *const u8) -> DwarfReader {
|
||||
DwarfReader { ptr: ptr }
|
||||
}
|
||||
|
||||
// DWARF streams are packed, so e.g. a u32 would not necessarily be aligned
|
||||
// on a 4-byte boundary. This may cause problems on platforms with strict
|
||||
// alignment requirements. By wrapping data in a "packed" struct, we are
|
||||
// telling the backend to generate "misalignment-safe" code.
|
||||
unsafe fn read<T: Copy>(&mut self) -> T {
|
||||
let result = *(self.ptr as *const Unaligned<T>);
|
||||
self.ptr = self.ptr.offset(mem::size_of::<T>() as isize);
|
||||
result.get()
|
||||
}
|
||||
|
||||
// ULEB128 and SLEB128 encodings are defined in Section 7.6 - "Variable
|
||||
// Length Data".
|
||||
unsafe fn read_uleb128(&mut self) -> u64 {
|
||||
let mut shift: usize = 0;
|
||||
let mut result: u64 = 0;
|
||||
let mut byte: u8;
|
||||
loop {
|
||||
byte = self.read::<u8>();
|
||||
result |= ((byte & 0x7F) as u64) << shift;
|
||||
shift += 7;
|
||||
if byte & 0x80 == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
unsafe fn read_sleb128(&mut self) -> i64 {
|
||||
let mut shift: usize = 0;
|
||||
let mut result: u64 = 0;
|
||||
let mut byte: u8;
|
||||
loop {
|
||||
byte = self.read::<u8>();
|
||||
result |= ((byte & 0x7F) as u64) << shift;
|
||||
shift += 7;
|
||||
if byte & 0x80 == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// sign-extend
|
||||
if shift < 8 * mem::size_of::<u64>() && (byte & 0x40) != 0 {
|
||||
result |= (!0 as u64) << shift;
|
||||
}
|
||||
result as i64
|
||||
}
|
||||
|
||||
unsafe fn read_encoded_pointer(&mut self, encoding: u8) -> usize {
|
||||
fn round_up(unrounded: usize, align: usize) -> usize {
|
||||
debug_assert!(align.is_power_of_two());
|
||||
(unrounded + align - 1) & !(align - 1)
|
||||
}
|
||||
|
||||
debug_assert!(encoding != DW_EH_PE_omit);
|
||||
|
||||
// DW_EH_PE_aligned implies it's an absolute pointer value
|
||||
if encoding == DW_EH_PE_aligned {
|
||||
self.ptr = round_up(self.ptr as usize, mem::size_of::<usize>()) as *const u8;
|
||||
return self.read::<usize>()
|
||||
}
|
||||
|
||||
let value_ptr = self.ptr;
|
||||
let mut result = match encoding & 0x0F {
|
||||
DW_EH_PE_absptr => self.read::<usize>(),
|
||||
DW_EH_PE_uleb128 => self.read_uleb128() as usize,
|
||||
DW_EH_PE_udata2 => self.read::<u16>() as usize,
|
||||
DW_EH_PE_udata4 => self.read::<u32>() as usize,
|
||||
DW_EH_PE_udata8 => self.read::<u64>() as usize,
|
||||
DW_EH_PE_sleb128 => self.read_sleb128() as usize,
|
||||
DW_EH_PE_sdata2 => self.read::<i16>() as usize,
|
||||
DW_EH_PE_sdata4 => self.read::<i32>() as usize,
|
||||
DW_EH_PE_sdata8 => self.read::<i64>() as usize,
|
||||
_ => panic!(),
|
||||
};
|
||||
|
||||
result += match encoding & 0x70 {
|
||||
DW_EH_PE_absptr => 0,
|
||||
// relative to address of the encoded value, despite the name
|
||||
DW_EH_PE_pcrel => value_ptr as usize,
|
||||
_ => panic!(),
|
||||
};
|
||||
|
||||
if encoding & DW_EH_PE_indirect != 0 {
|
||||
result = *(result as *const usize);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
fn encoding_size(encoding: u8) -> usize {
|
||||
if encoding == DW_EH_PE_omit {
|
||||
return 0
|
||||
}
|
||||
|
||||
match encoding & 0x0F {
|
||||
DW_EH_PE_absptr => mem::size_of::<usize>(),
|
||||
DW_EH_PE_udata2 => 2,
|
||||
DW_EH_PE_udata4 => 4,
|
||||
DW_EH_PE_udata8 => 8,
|
||||
DW_EH_PE_sdata2 => 2,
|
||||
DW_EH_PE_sdata4 => 4,
|
||||
DW_EH_PE_sdata8 => 8,
|
||||
_ => panic!()
|
||||
}
|
||||
}
|
||||
|
||||
pub enum EHAction {
|
||||
None,
|
||||
Cleanup(usize),
|
||||
Catch(usize),
|
||||
Terminate,
|
||||
}
|
||||
|
||||
unsafe fn find_eh_action(lsda: *const u8, func_start: usize, ip: usize,
|
||||
exn_name: CSlice<u8>) -> EHAction {
|
||||
if lsda.is_null() {
|
||||
return EHAction::None
|
||||
}
|
||||
|
||||
let mut reader = DwarfReader::new(lsda);
|
||||
|
||||
let start_encoding = reader.read::<u8>();
|
||||
// base address for landing pad offsets
|
||||
let lpad_base = if start_encoding != DW_EH_PE_omit {
|
||||
reader.read_encoded_pointer(start_encoding)
|
||||
} else {
|
||||
func_start
|
||||
};
|
||||
|
||||
let ttype_encoding = reader.read::<u8>();
|
||||
let ttype_encoding_size = encoding_size(ttype_encoding) as isize;
|
||||
|
||||
let class_info;
|
||||
if ttype_encoding != DW_EH_PE_omit {
|
||||
let class_info_offset = reader.read_uleb128();
|
||||
class_info = reader.ptr.offset(class_info_offset as isize);
|
||||
} else {
|
||||
class_info = ptr::null();
|
||||
}
|
||||
assert!(!class_info.is_null());
|
||||
|
||||
let call_site_encoding = reader.read::<u8>();
|
||||
let call_site_table_length = reader.read_uleb128();
|
||||
let action_table = reader.ptr.offset(call_site_table_length as isize);
|
||||
|
||||
while reader.ptr < action_table {
|
||||
let cs_start = reader.read_encoded_pointer(call_site_encoding);
|
||||
let cs_len = reader.read_encoded_pointer(call_site_encoding);
|
||||
let cs_lpad = reader.read_encoded_pointer(call_site_encoding);
|
||||
let cs_action = reader.read_uleb128();
|
||||
|
||||
if ip < func_start + cs_start {
|
||||
// Callsite table is sorted by cs_start, so if we've passed the ip, we
|
||||
// may stop searching.
|
||||
break
|
||||
}
|
||||
if ip > func_start + cs_start + cs_len {
|
||||
continue
|
||||
}
|
||||
|
||||
if cs_lpad == 0 {
|
||||
return EHAction::None
|
||||
}
|
||||
|
||||
let lpad = lpad_base + cs_lpad;
|
||||
if cs_action == 0 {
|
||||
return EHAction::Cleanup(lpad)
|
||||
}
|
||||
|
||||
let action_entry = action_table.offset((cs_action - 1) as isize);
|
||||
let mut action_reader = DwarfReader::new(action_entry);
|
||||
loop {
|
||||
let type_info_offset = action_reader.read_sleb128() as isize;
|
||||
let action_offset = action_reader.clone().read_sleb128() as isize;
|
||||
assert!(type_info_offset >= 0);
|
||||
|
||||
if type_info_offset > 0 {
|
||||
let type_info_ptr_ptr = class_info.offset(-type_info_offset * ttype_encoding_size);
|
||||
let type_info_ptr = DwarfReader::new(type_info_ptr_ptr)
|
||||
.read_encoded_pointer(ttype_encoding);
|
||||
let type_info = *(type_info_ptr as *const CSlice<u8>);
|
||||
|
||||
if type_info.as_ref() == exn_name.as_ref() {
|
||||
return EHAction::Catch(lpad)
|
||||
}
|
||||
|
||||
if type_info.len() == 0 {
|
||||
// This is a catch-all clause. We don't compare type_info_ptr with null here
|
||||
// because, in PIC mode, the OR1K LLVM backend emits a literal zero
|
||||
// encoded with DW_EH_PE_pcrel, which of course doesn't result in
|
||||
// a proper null pointer.
|
||||
return EHAction::Catch(lpad)
|
||||
}
|
||||
}
|
||||
|
||||
if action_offset == 0 {
|
||||
break
|
||||
} else {
|
||||
action_reader.ptr = action_reader.ptr.offset(action_offset)
|
||||
}
|
||||
}
|
||||
|
||||
return EHAction::None
|
||||
}
|
||||
|
||||
// the function has a personality but no landing pads; this is fine
|
||||
EHAction::None
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Exception<'a> {
|
||||
pub name: CSlice<'a, u8>,
|
||||
pub file: CSlice<'a, u8>,
|
||||
pub line: u32,
|
||||
pub column: u32,
|
||||
pub function: CSlice<'a, u8>,
|
||||
pub message: CSlice<'a, u8>,
|
||||
pub param: [i64; 3]
|
||||
}
|
||||
|
||||
const EXCEPTION_CLASS: uw::_Unwind_Exception_Class = 0x4d_4c_42_53_41_52_54_51; /* 'MLBSARTQ' */
|
||||
|
||||
const MAX_BACKTRACE_SIZE: usize = 128;
|
||||
|
||||
#[repr(C)]
|
||||
struct ExceptionInfo {
|
||||
uw_exception: uw::_Unwind_Exception,
|
||||
exception: Option<Exception<'static>>,
|
||||
handled: bool,
|
||||
backtrace: [usize; MAX_BACKTRACE_SIZE],
|
||||
backtrace_size: usize
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX
|
||||
|
||||
#[cfg(any(target_arch = "or1k"))]
|
||||
const UNWIND_DATA_REG: (i32, i32) = (3, 4); // R3, R4
|
||||
|
||||
#[export_name="__artiq_personality"]
|
||||
pub extern fn personality(version: c_int,
|
||||
actions: uw::_Unwind_Action,
|
||||
uw_exception_class: uw::_Unwind_Exception_Class,
|
||||
uw_exception: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context)
|
||||
-> uw::_Unwind_Reason_Code {
|
||||
unsafe {
|
||||
if version != 1 || uw_exception_class != EXCEPTION_CLASS {
|
||||
return uw::_URC_FATAL_PHASE1_ERROR
|
||||
}
|
||||
|
||||
let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8;
|
||||
let ip = uw::_Unwind_GetIP(context) - 1;
|
||||
let func_start = uw::_Unwind_GetRegionStart(context);
|
||||
|
||||
let exception_info = &mut *(uw_exception as *mut ExceptionInfo);
|
||||
let exception = &exception_info.exception.unwrap();
|
||||
|
||||
let eh_action = find_eh_action(lsda, func_start, ip, exception.name);
|
||||
if actions as u32 & uw::_UA_SEARCH_PHASE as u32 != 0 {
|
||||
match eh_action {
|
||||
EHAction::None |
|
||||
EHAction::Cleanup(_) => return uw::_URC_CONTINUE_UNWIND,
|
||||
EHAction::Catch(_) => return uw::_URC_HANDLER_FOUND,
|
||||
EHAction::Terminate => return uw::_URC_FATAL_PHASE1_ERROR,
|
||||
}
|
||||
} else {
|
||||
match eh_action {
|
||||
EHAction::None => return uw::_URC_CONTINUE_UNWIND,
|
||||
EHAction::Cleanup(lpad) |
|
||||
EHAction::Catch(lpad) => {
|
||||
if actions as u32 & uw::_UA_HANDLER_FRAME as u32 != 0 {
|
||||
exception_info.handled = true
|
||||
}
|
||||
|
||||
// Pass a pair of the unwinder exception and ARTIQ exception
|
||||
// (which immediately follows).
|
||||
uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0,
|
||||
uw_exception as uw::_Unwind_Word);
|
||||
uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1,
|
||||
exception as *const _ as uw::_Unwind_Word);
|
||||
uw::_Unwind_SetIP(context, lpad);
|
||||
return uw::_URC_INSTALL_CONTEXT;
|
||||
}
|
||||
EHAction::Terminate => return uw::_URC_FATAL_PHASE2_ERROR,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern fn cleanup(_unwind_code: uw::_Unwind_Reason_Code,
|
||||
uw_exception: *mut uw::_Unwind_Exception) {
|
||||
unsafe {
|
||||
let exception_info = &mut *(uw_exception as *mut ExceptionInfo);
|
||||
|
||||
exception_info.exception = None;
|
||||
}
|
||||
}
|
||||
|
||||
extern fn uncaught_exception(_version: c_int,
|
||||
actions: uw::_Unwind_Action,
|
||||
_uw_exception_class: uw::_Unwind_Exception_Class,
|
||||
uw_exception: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context,
|
||||
_stop_parameter: *mut c_void)
|
||||
-> uw::_Unwind_Reason_Code {
|
||||
unsafe {
|
||||
let exception_info = &mut *(uw_exception as *mut ExceptionInfo);
|
||||
|
||||
if exception_info.backtrace_size < exception_info.backtrace.len() {
|
||||
let ip = uw::_Unwind_GetIP(context);
|
||||
exception_info.backtrace[exception_info.backtrace_size] = ip;
|
||||
exception_info.backtrace_size += 1;
|
||||
}
|
||||
|
||||
if actions as u32 & uw::_UA_END_OF_STACK as u32 != 0 {
|
||||
::terminate(&exception_info.exception.unwrap(),
|
||||
exception_info.backtrace[..exception_info.backtrace_size].as_mut())
|
||||
} else {
|
||||
uw::_URC_NO_REASON
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We can unfortunately not use mem::zeroed in a static, so Option<> is used as a workaround.
|
||||
// See https://github.com/rust-lang/rust/issues/39498.
|
||||
static mut INFLIGHT: ExceptionInfo = ExceptionInfo {
|
||||
uw_exception: uw::_Unwind_Exception {
|
||||
exception_class: EXCEPTION_CLASS,
|
||||
exception_cleanup: cleanup,
|
||||
private: [0; uw::unwinder_private_data_size],
|
||||
},
|
||||
exception: None,
|
||||
handled: true,
|
||||
backtrace: [0; MAX_BACKTRACE_SIZE],
|
||||
backtrace_size: 0
|
||||
};
|
||||
|
||||
#[export_name="__artiq_raise"]
|
||||
#[unwind]
|
||||
pub unsafe extern fn raise(exception: *const Exception) -> ! {
|
||||
// Zing! The Exception<'a> as Exception<'static> cast is not really sound in case
|
||||
// the exception is ever captured. Fortunately, they currently aren't, and we save
|
||||
// on the hassle of having to allocate exceptions somewhere except on stack.
|
||||
INFLIGHT.exception = Some(mem::transmute::<Exception, Exception<'static>>(*exception));
|
||||
INFLIGHT.handled = false;
|
||||
|
||||
let result = uw::_Unwind_RaiseException(&mut INFLIGHT.uw_exception);
|
||||
assert!(result == uw::_URC_END_OF_STACK);
|
||||
|
||||
INFLIGHT.backtrace_size = 0;
|
||||
let _result = _Unwind_ForcedUnwind(&mut INFLIGHT.uw_exception,
|
||||
uncaught_exception, ptr::null_mut());
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
#[export_name="__artiq_reraise"]
|
||||
#[unwind]
|
||||
pub unsafe extern fn reraise() -> ! {
|
||||
use cslice::AsCSlice;
|
||||
|
||||
if INFLIGHT.handled {
|
||||
match INFLIGHT.exception {
|
||||
Some(ref exception) => raise(exception),
|
||||
None => raise(&Exception {
|
||||
name: "0:artiq.coredevice.exceptions.RuntimeError".as_c_slice(),
|
||||
file: file!().as_c_slice(),
|
||||
line: line!(),
|
||||
column: column!(),
|
||||
// https://github.com/rust-lang/rfcs/pull/1719
|
||||
function: "__artiq_reraise".as_c_slice(),
|
||||
message: "No active exception to reraise".as_c_slice(),
|
||||
param: [0, 0, 0]
|
||||
})
|
||||
}
|
||||
} else {
|
||||
uw::_Unwind_Resume(&mut INFLIGHT.uw_exception)
|
||||
}
|
||||
}
|
||||
|
||||
// Stub implementations for the functions the panic_unwind crate expects to be provided.
|
||||
// These all do nothing in libunwind, but aren't built for OR1K.
|
||||
pub mod stubs {
|
||||
#![allow(bad_style, unused_variables)]
|
||||
|
||||
use super::{uw, c_int};
|
||||
|
||||
#[export_name="_Unwind_GetIPInfo"]
|
||||
pub unsafe extern fn _Unwind_GetIPInfo(ctx: *mut uw::_Unwind_Context,
|
||||
ip_before_insn: *mut c_int) -> uw::_Unwind_Word {
|
||||
*ip_before_insn = 0;
|
||||
uw::_Unwind_GetIP(ctx)
|
||||
}
|
||||
|
||||
#[export_name="_Unwind_GetTextRelBase"]
|
||||
pub unsafe extern fn _Unwind_GetTextRelBase(ctx: *mut uw::_Unwind_Context) -> uw::_Unwind_Ptr {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[export_name="_Unwind_GetDataRelBase"]
|
||||
pub unsafe extern fn _Unwind_GetDataRelBase(ctx: *mut uw::_Unwind_Context) -> uw::_Unwind_Ptr {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,203 @@
|
|||
// Portions of the code in this file are derived from code by:
|
||||
//
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
#![allow(private_no_mangle_fns, non_camel_case_types)]
|
||||
|
||||
use core::{ptr, mem};
|
||||
use cslice::CSlice;
|
||||
use unwind as uw;
|
||||
use libc::{c_int, c_void};
|
||||
|
||||
use eh::dwarf::{self, EHAction};
|
||||
|
||||
type _Unwind_Stop_Fn = extern "C" fn(version: c_int,
|
||||
actions: uw::_Unwind_Action,
|
||||
exception_class: uw::_Unwind_Exception_Class,
|
||||
exception_object: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context,
|
||||
stop_parameter: *mut c_void)
|
||||
-> uw::_Unwind_Reason_Code;
|
||||
extern {
|
||||
fn _Unwind_ForcedUnwind(exception: *mut uw::_Unwind_Exception,
|
||||
stop_fn: _Unwind_Stop_Fn,
|
||||
stop_parameter: *mut c_void) -> uw::_Unwind_Reason_Code;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Exception<'a> {
|
||||
pub name: CSlice<'a, u8>,
|
||||
pub file: CSlice<'a, u8>,
|
||||
pub line: u32,
|
||||
pub column: u32,
|
||||
pub function: CSlice<'a, u8>,
|
||||
pub message: CSlice<'a, u8>,
|
||||
pub param: [i64; 3]
|
||||
}
|
||||
|
||||
const EXCEPTION_CLASS: uw::_Unwind_Exception_Class = 0x4d_4c_42_53_41_52_54_51; /* 'MLBSARTQ' */
|
||||
|
||||
const MAX_BACKTRACE_SIZE: usize = 128;
|
||||
|
||||
#[repr(C)]
|
||||
struct ExceptionInfo {
|
||||
uw_exception: uw::_Unwind_Exception,
|
||||
exception: Option<Exception<'static>>,
|
||||
handled: bool,
|
||||
backtrace: [usize; MAX_BACKTRACE_SIZE],
|
||||
backtrace_size: usize
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX
|
||||
|
||||
#[cfg(any(target_arch = "or1k"))]
|
||||
const UNWIND_DATA_REG: (i32, i32) = (3, 4); // R3, R4
|
||||
|
||||
#[export_name="__artiq_personality"]
|
||||
pub extern fn personality(version: c_int,
|
||||
actions: uw::_Unwind_Action,
|
||||
uw_exception_class: uw::_Unwind_Exception_Class,
|
||||
uw_exception: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context)
|
||||
-> uw::_Unwind_Reason_Code {
|
||||
unsafe {
|
||||
if version != 1 || uw_exception_class != EXCEPTION_CLASS {
|
||||
return uw::_URC_FATAL_PHASE1_ERROR
|
||||
}
|
||||
|
||||
let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8;
|
||||
let ip = uw::_Unwind_GetIP(context) - 1;
|
||||
let func_start = uw::_Unwind_GetRegionStart(context);
|
||||
|
||||
let exception_info = &mut *(uw_exception as *mut ExceptionInfo);
|
||||
let exception = &exception_info.exception.unwrap();
|
||||
|
||||
let eh_action = dwarf::find_eh_action(lsda, func_start, ip, exception.name);
|
||||
if actions as u32 & uw::_UA_SEARCH_PHASE as u32 != 0 {
|
||||
match eh_action {
|
||||
EHAction::None |
|
||||
EHAction::Cleanup(_) => return uw::_URC_CONTINUE_UNWIND,
|
||||
EHAction::Catch(_) => return uw::_URC_HANDLER_FOUND,
|
||||
EHAction::Terminate => return uw::_URC_FATAL_PHASE1_ERROR,
|
||||
}
|
||||
} else {
|
||||
match eh_action {
|
||||
EHAction::None => return uw::_URC_CONTINUE_UNWIND,
|
||||
EHAction::Cleanup(lpad) |
|
||||
EHAction::Catch(lpad) => {
|
||||
if actions as u32 & uw::_UA_HANDLER_FRAME as u32 != 0 {
|
||||
exception_info.handled = true
|
||||
}
|
||||
|
||||
// Pass a pair of the unwinder exception and ARTIQ exception
|
||||
// (which immediately follows).
|
||||
uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0,
|
||||
uw_exception as uw::_Unwind_Word);
|
||||
uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1,
|
||||
exception as *const _ as uw::_Unwind_Word);
|
||||
uw::_Unwind_SetIP(context, lpad);
|
||||
return uw::_URC_INSTALL_CONTEXT;
|
||||
}
|
||||
EHAction::Terminate => return uw::_URC_FATAL_PHASE2_ERROR,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern fn cleanup(_unwind_code: uw::_Unwind_Reason_Code,
|
||||
uw_exception: *mut uw::_Unwind_Exception) {
|
||||
unsafe {
|
||||
let exception_info = &mut *(uw_exception as *mut ExceptionInfo);
|
||||
|
||||
exception_info.exception = None;
|
||||
}
|
||||
}
|
||||
|
||||
extern fn uncaught_exception(_version: c_int,
|
||||
actions: uw::_Unwind_Action,
|
||||
_uw_exception_class: uw::_Unwind_Exception_Class,
|
||||
uw_exception: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context,
|
||||
_stop_parameter: *mut c_void)
|
||||
-> uw::_Unwind_Reason_Code {
|
||||
unsafe {
|
||||
let exception_info = &mut *(uw_exception as *mut ExceptionInfo);
|
||||
|
||||
if exception_info.backtrace_size < exception_info.backtrace.len() {
|
||||
let ip = uw::_Unwind_GetIP(context);
|
||||
exception_info.backtrace[exception_info.backtrace_size] = ip;
|
||||
exception_info.backtrace_size += 1;
|
||||
}
|
||||
|
||||
if actions as u32 & uw::_UA_END_OF_STACK as u32 != 0 {
|
||||
::terminate(&exception_info.exception.unwrap(),
|
||||
exception_info.backtrace[..exception_info.backtrace_size].as_mut())
|
||||
} else {
|
||||
uw::_URC_NO_REASON
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We can unfortunately not use mem::zeroed in a static, so Option<> is used as a workaround.
|
||||
// See https://github.com/rust-lang/rust/issues/39498.
|
||||
static mut INFLIGHT: ExceptionInfo = ExceptionInfo {
|
||||
uw_exception: uw::_Unwind_Exception {
|
||||
exception_class: EXCEPTION_CLASS,
|
||||
exception_cleanup: cleanup,
|
||||
private: [0; uw::unwinder_private_data_size],
|
||||
},
|
||||
exception: None,
|
||||
handled: true,
|
||||
backtrace: [0; MAX_BACKTRACE_SIZE],
|
||||
backtrace_size: 0
|
||||
};
|
||||
|
||||
#[export_name="__artiq_raise"]
|
||||
#[unwind(allowed)]
|
||||
pub unsafe extern fn raise(exception: *const Exception) -> ! {
|
||||
// Zing! The Exception<'a> to Exception<'static> transmute is not really sound in case
|
||||
// the exception is ever captured. Fortunately, they currently aren't, and we save
|
||||
// on the hassle of having to allocate exceptions somewhere except on stack.
|
||||
INFLIGHT.exception = Some(mem::transmute::<Exception, Exception<'static>>(*exception));
|
||||
INFLIGHT.handled = false;
|
||||
|
||||
let result = uw::_Unwind_RaiseException(&mut INFLIGHT.uw_exception);
|
||||
assert!(result == uw::_URC_END_OF_STACK);
|
||||
|
||||
INFLIGHT.backtrace_size = 0;
|
||||
let _result = _Unwind_ForcedUnwind(&mut INFLIGHT.uw_exception,
|
||||
uncaught_exception, ptr::null_mut());
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
#[export_name="__artiq_reraise"]
|
||||
#[unwind(allowed)]
|
||||
pub unsafe extern fn reraise() -> ! {
|
||||
use cslice::AsCSlice;
|
||||
|
||||
if INFLIGHT.handled {
|
||||
match INFLIGHT.exception {
|
||||
Some(ref exception) => raise(exception),
|
||||
None => raise(&Exception {
|
||||
name: "0:artiq.coredevice.exceptions.RuntimeError".as_c_slice(),
|
||||
file: file!().as_c_slice(),
|
||||
line: line!(),
|
||||
column: column!(),
|
||||
// https://github.com/rust-lang/rfcs/pull/1719
|
||||
function: "__artiq_reraise".as_c_slice(),
|
||||
message: "No active exception to reraise".as_c_slice(),
|
||||
param: [0, 0, 0]
|
||||
})
|
||||
}
|
||||
} else {
|
||||
uw::_Unwind_Resume(&mut INFLIGHT.uw_exception)
|
||||
}
|
||||
}
|
|
@ -19,6 +19,8 @@ void send_to_rtio_log(long long int timestamp, struct slice data);
|
|||
#define KERNELCPU_LAST_ADDRESS 0x4fffffff
|
||||
#define KSUPPORT_HEADER_SIZE 0x80
|
||||
|
||||
FILE *stderr;
|
||||
|
||||
/* called by libunwind */
|
||||
int fprintf(FILE *stream, const char *fmt, ...)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#![feature(lang_items, asm, libc, panic_unwind, unwind_attributes, global_allocator)]
|
||||
#![feature(lang_items, asm, panic_unwind, libc, unwind_attributes,
|
||||
panic_implementation, panic_info_message)]
|
||||
#![no_std]
|
||||
|
||||
extern crate unwind;
|
||||
|
@ -10,6 +11,7 @@ extern crate alloc_stub;
|
|||
extern crate std_artiq as std;
|
||||
|
||||
extern crate board;
|
||||
extern crate eh;
|
||||
extern crate dyld;
|
||||
extern crate proto;
|
||||
extern crate amp;
|
||||
|
@ -52,10 +54,26 @@ macro_rules! recv {
|
|||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[lang = "panic_fmt"]
|
||||
pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, line: u32) -> ! {
|
||||
send(&Log(format_args!("panic at {}:{}: {}\n", file, line, args)));
|
||||
#[no_mangle] // https://github.com/rust-lang/rust/issues/{38281,51647}
|
||||
#[lang = "oom"] // https://github.com/rust-lang/rust/issues/51540
|
||||
pub fn oom(_layout: core::alloc::Layout) -> ! {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
#[no_mangle] // https://github.com/rust-lang/rust/issues/{38281,51647}
|
||||
#[panic_implementation]
|
||||
pub fn panic_fmt(info: &core::panic::PanicInfo) -> ! {
|
||||
if let Some(location) = info.location() {
|
||||
send(&Log(format_args!("panic at {}:{}:{}",
|
||||
location.file(), location.line(), location.column())));
|
||||
} else {
|
||||
send(&Log(format_args!("panic at unknown location")));
|
||||
}
|
||||
if let Some(message) = info.message() {
|
||||
send(&Log(format_args!("{}\n", message)));
|
||||
} else {
|
||||
send(&Log(format_args!("\n")));
|
||||
}
|
||||
send(&RunAborted);
|
||||
loop {}
|
||||
}
|
||||
|
@ -72,7 +90,7 @@ macro_rules! println {
|
|||
macro_rules! raise {
|
||||
($name:expr, $message:expr, $param0:expr, $param1:expr, $param2:expr) => ({
|
||||
use cslice::AsCSlice;
|
||||
let exn = $crate::eh::Exception {
|
||||
let exn = $crate::eh_artiq::Exception {
|
||||
name: concat!("0:artiq.coredevice.exceptions.", $name).as_c_slice(),
|
||||
file: file!().as_c_slice(),
|
||||
line: line!(),
|
||||
|
@ -83,14 +101,14 @@ macro_rules! raise {
|
|||
param: [$param0, $param1, $param2]
|
||||
};
|
||||
#[allow(unused_unsafe)]
|
||||
unsafe { $crate::eh::raise(&exn) }
|
||||
unsafe { $crate::eh_artiq::raise(&exn) }
|
||||
});
|
||||
($name:expr, $message:expr) => ({
|
||||
raise!($name, $message, 0, 0, 0)
|
||||
});
|
||||
}
|
||||
|
||||
pub mod eh;
|
||||
mod eh_artiq;
|
||||
mod api;
|
||||
mod rtio;
|
||||
mod nrt_bus;
|
||||
|
@ -114,6 +132,7 @@ pub extern fn send_to_rtio_log(timestamp: i64, text: CSlice<u8>) {
|
|||
rtio::log(timestamp, text.as_ref())
|
||||
}
|
||||
|
||||
#[unwind(aborts)]
|
||||
extern fn rpc_send(service: u32, tag: CSlice<u8>, data: *const *const ()) {
|
||||
while !rpc_queue::empty() {}
|
||||
send(&RpcSend {
|
||||
|
@ -124,6 +143,7 @@ extern fn rpc_send(service: u32, tag: CSlice<u8>, data: *const *const ()) {
|
|||
})
|
||||
}
|
||||
|
||||
#[unwind(aborts)]
|
||||
extern fn rpc_send_async(service: u32, tag: CSlice<u8>, data: *const *const ()) {
|
||||
while rpc_queue::full() {}
|
||||
rpc_queue::enqueue(|mut slice| {
|
||||
|
@ -146,6 +166,7 @@ extern fn rpc_send_async(service: u32, tag: CSlice<u8>, data: *const *const ())
|
|||
})
|
||||
}
|
||||
|
||||
#[unwind(allowed)]
|
||||
extern fn rpc_recv(slot: *mut ()) -> usize {
|
||||
send(&RpcRecvRequest(slot));
|
||||
recv!(&RpcRecvReply(ref result) => {
|
||||
|
@ -153,7 +174,7 @@ extern fn rpc_recv(slot: *mut ()) -> usize {
|
|||
&Ok(alloc_size) => alloc_size,
|
||||
&Err(ref exception) =>
|
||||
unsafe {
|
||||
eh::raise(&eh::Exception {
|
||||
eh_artiq::raise(&eh_artiq::Exception {
|
||||
name: exception.name.as_bytes().as_c_slice(),
|
||||
file: exception.file.as_bytes().as_c_slice(),
|
||||
line: exception.line,
|
||||
|
@ -167,7 +188,7 @@ extern fn rpc_recv(slot: *mut ()) -> usize {
|
|||
})
|
||||
}
|
||||
|
||||
fn terminate(exception: &eh::Exception, backtrace: &mut [usize]) -> ! {
|
||||
fn terminate(exception: &eh_artiq::Exception, backtrace: &mut [usize]) -> ! {
|
||||
let mut cursor = 0;
|
||||
for index in 0..backtrace.len() {
|
||||
if backtrace[index] > kernel_proto::KERNELCPU_PAYLOAD_ADDRESS {
|
||||
|
@ -193,6 +214,7 @@ fn terminate(exception: &eh::Exception, backtrace: &mut [usize]) -> ! {
|
|||
loop {}
|
||||
}
|
||||
|
||||
#[unwind(allowed)]
|
||||
extern fn watchdog_set(ms: i64) -> i32 {
|
||||
if ms < 0 {
|
||||
raise!("ValueError", "cannot set a watchdog with a negative timeout")
|
||||
|
@ -202,10 +224,12 @@ extern fn watchdog_set(ms: i64) -> i32 {
|
|||
recv!(&WatchdogSetReply { id } => id) as i32
|
||||
}
|
||||
|
||||
#[unwind(aborts)]
|
||||
extern fn watchdog_clear(id: i32) {
|
||||
send(&WatchdogClear { id: id as usize })
|
||||
}
|
||||
|
||||
#[unwind(aborts)]
|
||||
extern fn cache_get(key: CSlice<u8>) -> CSlice<'static, i32> {
|
||||
send(&CacheGetRequest {
|
||||
key: str::from_utf8(key.as_ref()).unwrap()
|
||||
|
@ -213,6 +237,7 @@ extern fn cache_get(key: CSlice<u8>) -> CSlice<'static, i32> {
|
|||
recv!(&CacheGetReply { value } => value.as_c_slice())
|
||||
}
|
||||
|
||||
#[unwind(allowed)]
|
||||
extern fn cache_put(key: CSlice<u8>, list: CSlice<i32>) {
|
||||
send(&CachePutRequest {
|
||||
key: str::from_utf8(key.as_ref()).unwrap(),
|
||||
|
@ -246,6 +271,7 @@ fn dma_record_flush() {
|
|||
}
|
||||
}
|
||||
|
||||
#[unwind(allowed)]
|
||||
extern fn dma_record_start(name: CSlice<u8>) {
|
||||
let name = str::from_utf8(name.as_ref()).unwrap();
|
||||
|
||||
|
@ -265,6 +291,7 @@ extern fn dma_record_start(name: CSlice<u8>) {
|
|||
}
|
||||
}
|
||||
|
||||
#[unwind(allowed)]
|
||||
extern fn dma_record_stop(duration: i64) {
|
||||
unsafe {
|
||||
dma_record_flush();
|
||||
|
@ -286,10 +313,12 @@ extern fn dma_record_stop(duration: i64) {
|
|||
}
|
||||
}
|
||||
|
||||
#[unwind(aborts)]
|
||||
extern fn dma_record_output(timestamp: i64, channel: i32, address: i32, word: i32) {
|
||||
dma_record_output_wide(timestamp, channel, address, [word].as_c_slice())
|
||||
}
|
||||
|
||||
#[unwind(aborts)]
|
||||
extern fn dma_record_output_wide(timestamp: i64, channel: i32, address: i32, words: CSlice<i32>) {
|
||||
assert!(words.len() <= 16); // enforce the hardware limit
|
||||
|
||||
|
@ -338,6 +367,7 @@ extern fn dma_record_output_wide(timestamp: i64, channel: i32, address: i32, wor
|
|||
}
|
||||
}
|
||||
|
||||
#[unwind(aborts)]
|
||||
extern fn dma_erase(name: CSlice<u8>) {
|
||||
let name = str::from_utf8(name.as_ref()).unwrap();
|
||||
|
||||
|
@ -350,6 +380,7 @@ struct DmaTrace {
|
|||
address: i32,
|
||||
}
|
||||
|
||||
#[unwind(allowed)]
|
||||
extern fn dma_retrieve(name: CSlice<u8>) -> DmaTrace {
|
||||
let name = str::from_utf8(name.as_ref()).unwrap();
|
||||
|
||||
|
@ -369,6 +400,7 @@ extern fn dma_retrieve(name: CSlice<u8>) -> DmaTrace {
|
|||
})
|
||||
}
|
||||
|
||||
#[unwind(allowed)]
|
||||
extern fn dma_playback(timestamp: i64, ptr: i32) {
|
||||
assert!(ptr % 64 == 0);
|
||||
|
||||
|
@ -483,12 +515,13 @@ pub unsafe fn main() {
|
|||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[unwind(allowed)]
|
||||
pub extern fn exception_handler(vect: u32, _regs: *const u32, pc: u32, ea: u32) {
|
||||
panic!("exception {:?} at PC 0x{:x}, EA 0x{:x}", vect, pc, ea)
|
||||
}
|
||||
|
||||
// We don't export this because libbase does.
|
||||
// #[no_mangle]
|
||||
#[no_mangle]
|
||||
#[unwind(allowed)]
|
||||
pub extern fn abort() {
|
||||
panic!("aborted")
|
||||
}
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
#![feature(alloc, allocator_api)]
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use core::{mem, fmt};
|
||||
use alloc::allocator::{Layout, AllocErr, Alloc};
|
||||
use core::{ptr, mem, fmt};
|
||||
use core::alloc::{GlobalAlloc, Layout};
|
||||
|
||||
// The minimum alignment guaranteed by the architecture.
|
||||
const MIN_ALIGN: usize = 4;
|
||||
|
@ -42,10 +39,10 @@ impl ListAlloc {
|
|||
}
|
||||
}
|
||||
|
||||
unsafe impl<'a> Alloc for &'a ListAlloc {
|
||||
unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
|
||||
unsafe impl GlobalAlloc for ListAlloc {
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
if layout.align() > MIN_ALIGN {
|
||||
return Err(AllocErr::Unsupported { details: "alignment too large" })
|
||||
panic!("cannot allocate with alignment {}", layout.align())
|
||||
}
|
||||
|
||||
let header_size = mem::size_of::<Header>();
|
||||
|
@ -83,7 +80,7 @@ unsafe impl<'a> Alloc for &'a ListAlloc {
|
|||
|
||||
if (*curr).size >= size {
|
||||
(*curr).magic = MAGIC_BUSY;
|
||||
return Ok(curr.offset(1) as *mut u8)
|
||||
return curr.offset(1) as *mut u8
|
||||
}
|
||||
},
|
||||
_ => panic!("heap corruption detected at {:p}", curr)
|
||||
|
@ -92,20 +89,16 @@ unsafe impl<'a> Alloc for &'a ListAlloc {
|
|||
curr = (*curr).next;
|
||||
}
|
||||
|
||||
Err(AllocErr::Exhausted { request: layout })
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
unsafe fn dealloc(&mut self, ptr: *mut u8, _layout: Layout) {
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
|
||||
let curr = (ptr as *mut Header).offset(-1);
|
||||
if (*curr).magic != MAGIC_BUSY {
|
||||
panic!("heap corruption detected at {:p}", curr)
|
||||
}
|
||||
(*curr).magic = MAGIC_FREE;
|
||||
}
|
||||
|
||||
fn oom(&mut self, err: AllocErr) -> ! {
|
||||
panic!("heap view: {}\ncannot allocate: {:?}", self, err)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ListAlloc {
|
||||
|
|
|
@ -3,16 +3,16 @@
|
|||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::allocator::{Layout, AllocErr, Alloc};
|
||||
use core::alloc::{Layout, GlobalAlloc};
|
||||
|
||||
pub struct StubAlloc;
|
||||
|
||||
unsafe impl<'a> Alloc for &'a StubAlloc {
|
||||
unsafe fn alloc(&mut self, _layout: Layout) -> Result<*mut u8, AllocErr> {
|
||||
unsafe impl GlobalAlloc for StubAlloc {
|
||||
unsafe fn alloc(&self, _layout: Layout) -> *mut u8 {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
unsafe fn dealloc(&mut self, _ptr: *mut u8, _layout: Layout) {
|
||||
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
authors = ["M-Labs"]
|
||||
name = "eh"
|
||||
version = "0.0.0"
|
||||
|
||||
[lib]
|
||||
name = "eh"
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
cslice = { version = "0.3" }
|
|
@ -0,0 +1,243 @@
|
|||
#![allow(non_upper_case_globals, dead_code)]
|
||||
|
||||
use core::{ptr, mem};
|
||||
use cslice::CSlice;
|
||||
|
||||
const DW_EH_PE_omit: u8 = 0xFF;
|
||||
const DW_EH_PE_absptr: u8 = 0x00;
|
||||
|
||||
const DW_EH_PE_uleb128: u8 = 0x01;
|
||||
const DW_EH_PE_udata2: u8 = 0x02;
|
||||
const DW_EH_PE_udata4: u8 = 0x03;
|
||||
const DW_EH_PE_udata8: u8 = 0x04;
|
||||
const DW_EH_PE_sleb128: u8 = 0x09;
|
||||
const DW_EH_PE_sdata2: u8 = 0x0A;
|
||||
const DW_EH_PE_sdata4: u8 = 0x0B;
|
||||
const DW_EH_PE_sdata8: u8 = 0x0C;
|
||||
|
||||
const DW_EH_PE_pcrel: u8 = 0x10;
|
||||
const DW_EH_PE_textrel: u8 = 0x20;
|
||||
const DW_EH_PE_datarel: u8 = 0x30;
|
||||
const DW_EH_PE_funcrel: u8 = 0x40;
|
||||
const DW_EH_PE_aligned: u8 = 0x50;
|
||||
|
||||
const DW_EH_PE_indirect: u8 = 0x80;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct DwarfReader {
|
||||
pub ptr: *const u8,
|
||||
}
|
||||
|
||||
impl DwarfReader {
|
||||
fn new(ptr: *const u8) -> DwarfReader {
|
||||
DwarfReader { ptr: ptr }
|
||||
}
|
||||
|
||||
// DWARF streams are packed, so e.g. a u32 would not necessarily be aligned
|
||||
// on a 4-byte boundary. This may cause problems on platforms with strict
|
||||
// alignment requirements. By wrapping data in a "packed" struct, we are
|
||||
// telling the backend to generate "misalignment-safe" code.
|
||||
unsafe fn read<T: Copy>(&mut self) -> T {
|
||||
let result = ptr::read_unaligned(self.ptr as *const T);
|
||||
self.ptr = self.ptr.offset(mem::size_of::<T>() as isize);
|
||||
result
|
||||
}
|
||||
|
||||
// ULEB128 and SLEB128 encodings are defined in Section 7.6 - "Variable
|
||||
// Length Data".
|
||||
unsafe fn read_uleb128(&mut self) -> u64 {
|
||||
let mut shift: usize = 0;
|
||||
let mut result: u64 = 0;
|
||||
let mut byte: u8;
|
||||
loop {
|
||||
byte = self.read::<u8>();
|
||||
result |= ((byte & 0x7F) as u64) << shift;
|
||||
shift += 7;
|
||||
if byte & 0x80 == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
unsafe fn read_sleb128(&mut self) -> i64 {
|
||||
let mut shift: usize = 0;
|
||||
let mut result: u64 = 0;
|
||||
let mut byte: u8;
|
||||
loop {
|
||||
byte = self.read::<u8>();
|
||||
result |= ((byte & 0x7F) as u64) << shift;
|
||||
shift += 7;
|
||||
if byte & 0x80 == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// sign-extend
|
||||
if shift < 8 * mem::size_of::<u64>() && (byte & 0x40) != 0 {
|
||||
result |= (!0 as u64) << shift;
|
||||
}
|
||||
result as i64
|
||||
}
|
||||
|
||||
unsafe fn read_encoded_pointer(&mut self, encoding: u8) -> usize {
|
||||
fn round_up(unrounded: usize, align: usize) -> usize {
|
||||
debug_assert!(align.is_power_of_two());
|
||||
(unrounded + align - 1) & !(align - 1)
|
||||
}
|
||||
|
||||
debug_assert!(encoding != DW_EH_PE_omit);
|
||||
|
||||
// DW_EH_PE_aligned implies it's an absolute pointer value
|
||||
if encoding == DW_EH_PE_aligned {
|
||||
self.ptr = round_up(self.ptr as usize, mem::size_of::<usize>()) as *const u8;
|
||||
return self.read::<usize>()
|
||||
}
|
||||
|
||||
let value_ptr = self.ptr;
|
||||
let mut result = match encoding & 0x0F {
|
||||
DW_EH_PE_absptr => self.read::<usize>(),
|
||||
DW_EH_PE_uleb128 => self.read_uleb128() as usize,
|
||||
DW_EH_PE_udata2 => self.read::<u16>() as usize,
|
||||
DW_EH_PE_udata4 => self.read::<u32>() as usize,
|
||||
DW_EH_PE_udata8 => self.read::<u64>() as usize,
|
||||
DW_EH_PE_sleb128 => self.read_sleb128() as usize,
|
||||
DW_EH_PE_sdata2 => self.read::<i16>() as usize,
|
||||
DW_EH_PE_sdata4 => self.read::<i32>() as usize,
|
||||
DW_EH_PE_sdata8 => self.read::<i64>() as usize,
|
||||
_ => panic!(),
|
||||
};
|
||||
|
||||
result += match encoding & 0x70 {
|
||||
DW_EH_PE_absptr => 0,
|
||||
// relative to address of the encoded value, despite the name
|
||||
DW_EH_PE_pcrel => value_ptr as usize,
|
||||
_ => panic!(),
|
||||
};
|
||||
|
||||
if encoding & DW_EH_PE_indirect != 0 {
|
||||
result = *(result as *const usize);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
fn encoding_size(encoding: u8) -> usize {
|
||||
if encoding == DW_EH_PE_omit {
|
||||
return 0
|
||||
}
|
||||
|
||||
match encoding & 0x0F {
|
||||
DW_EH_PE_absptr => mem::size_of::<usize>(),
|
||||
DW_EH_PE_udata2 => 2,
|
||||
DW_EH_PE_udata4 => 4,
|
||||
DW_EH_PE_udata8 => 8,
|
||||
DW_EH_PE_sdata2 => 2,
|
||||
DW_EH_PE_sdata4 => 4,
|
||||
DW_EH_PE_sdata8 => 8,
|
||||
_ => panic!()
|
||||
}
|
||||
}
|
||||
|
||||
pub enum EHAction {
|
||||
None,
|
||||
Cleanup(usize),
|
||||
Catch(usize),
|
||||
Terminate,
|
||||
}
|
||||
|
||||
pub unsafe fn find_eh_action(lsda: *const u8, func_start: usize, ip: usize,
|
||||
exn_name: CSlice<u8>) -> EHAction {
|
||||
if lsda.is_null() {
|
||||
return EHAction::None
|
||||
}
|
||||
|
||||
let mut reader = DwarfReader::new(lsda);
|
||||
|
||||
let start_encoding = reader.read::<u8>();
|
||||
// base address for landing pad offsets
|
||||
let lpad_base = if start_encoding != DW_EH_PE_omit {
|
||||
reader.read_encoded_pointer(start_encoding)
|
||||
} else {
|
||||
func_start
|
||||
};
|
||||
|
||||
let ttype_encoding = reader.read::<u8>();
|
||||
let ttype_encoding_size = encoding_size(ttype_encoding) as isize;
|
||||
|
||||
let class_info;
|
||||
if ttype_encoding != DW_EH_PE_omit {
|
||||
let class_info_offset = reader.read_uleb128();
|
||||
class_info = reader.ptr.offset(class_info_offset as isize);
|
||||
} else {
|
||||
class_info = ptr::null();
|
||||
}
|
||||
assert!(!class_info.is_null());
|
||||
|
||||
let call_site_encoding = reader.read::<u8>();
|
||||
let call_site_table_length = reader.read_uleb128();
|
||||
let action_table = reader.ptr.offset(call_site_table_length as isize);
|
||||
|
||||
while reader.ptr < action_table {
|
||||
let cs_start = reader.read_encoded_pointer(call_site_encoding);
|
||||
let cs_len = reader.read_encoded_pointer(call_site_encoding);
|
||||
let cs_lpad = reader.read_encoded_pointer(call_site_encoding);
|
||||
let cs_action = reader.read_uleb128();
|
||||
|
||||
if ip < func_start + cs_start {
|
||||
// Callsite table is sorted by cs_start, so if we've passed the ip, we
|
||||
// may stop searching.
|
||||
break
|
||||
}
|
||||
if ip > func_start + cs_start + cs_len {
|
||||
continue
|
||||
}
|
||||
|
||||
if cs_lpad == 0 {
|
||||
return EHAction::None
|
||||
}
|
||||
|
||||
let lpad = lpad_base + cs_lpad;
|
||||
if cs_action == 0 {
|
||||
return EHAction::Cleanup(lpad)
|
||||
}
|
||||
|
||||
let action_entry = action_table.offset((cs_action - 1) as isize);
|
||||
let mut action_reader = DwarfReader::new(action_entry);
|
||||
loop {
|
||||
let type_info_offset = action_reader.read_sleb128() as isize;
|
||||
let action_offset = action_reader.clone().read_sleb128() as isize;
|
||||
assert!(type_info_offset >= 0);
|
||||
|
||||
if type_info_offset > 0 {
|
||||
let type_info_ptr_ptr = class_info.offset(-type_info_offset * ttype_encoding_size);
|
||||
let type_info_ptr = DwarfReader::new(type_info_ptr_ptr)
|
||||
.read_encoded_pointer(ttype_encoding);
|
||||
let type_info = *(type_info_ptr as *const CSlice<u8>);
|
||||
|
||||
if type_info.as_ref() == exn_name.as_ref() {
|
||||
return EHAction::Catch(lpad)
|
||||
}
|
||||
|
||||
if type_info.len() == 0 {
|
||||
// This is a catch-all clause. We don't compare type_info_ptr with null here
|
||||
// because, in PIC mode, the OR1K LLVM backend emits a literal zero
|
||||
// encoded with DW_EH_PE_pcrel, which of course doesn't result in
|
||||
// a proper null pointer.
|
||||
return EHAction::Catch(lpad)
|
||||
}
|
||||
}
|
||||
|
||||
if action_offset == 0 {
|
||||
break
|
||||
} else {
|
||||
action_reader.ptr = action_reader.ptr.offset(action_offset)
|
||||
}
|
||||
}
|
||||
|
||||
return EHAction::None
|
||||
}
|
||||
|
||||
// the function has a personality but no landing pads; this is fine
|
||||
EHAction::None
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// This is the Rust personality function, adapted for use in ARTIQ. We never actually panic
|
||||
// from Rust or recover from Rust exceptions (there's nothing to catch the panics), but we
|
||||
// need a personality function to step back through Rust frames in order to make a backtrace.
|
||||
//
|
||||
// By design, this personality function is only ever called in the search phase, although
|
||||
// to keep things simple and close to upstream, it is not modified
|
||||
#![allow(private_no_mangle_fns)]
|
||||
|
||||
use unwind as uw;
|
||||
use libc::{c_int, uintptr_t};
|
||||
use cslice::AsCSlice;
|
||||
|
||||
use dwarf::{self, EHAction};
|
||||
|
||||
// Register ids were lifted from LLVM's TargetLowering::getExceptionPointerRegister()
|
||||
// and TargetLowering::getExceptionSelectorRegister() for each architecture,
|
||||
// then mapped to DWARF register numbers via register definition tables
|
||||
// (typically <arch>RegisterInfo.td, search for "DwarfRegNum").
|
||||
// See also http://llvm.org/docs/WritingAnLLVMBackend.html#defining-a-register.
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
const UNWIND_DATA_REG: (i32, i32) = (0, 2); // EAX, EDX
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX
|
||||
|
||||
#[cfg(any(target_arch = "or1k"))]
|
||||
const UNWIND_DATA_REG: (i32, i32) = (3, 4); // R3, R4
|
||||
|
||||
// The following code is based on GCC's C and C++ personality routines. For reference, see:
|
||||
// https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc
|
||||
// https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c
|
||||
#[lang = "eh_personality"]
|
||||
#[no_mangle]
|
||||
#[allow(unused)]
|
||||
unsafe extern "C" fn rust_eh_personality(version: c_int,
|
||||
actions: uw::_Unwind_Action,
|
||||
exception_class: uw::_Unwind_Exception_Class,
|
||||
exception_object: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context)
|
||||
-> uw::_Unwind_Reason_Code {
|
||||
if version != 1 {
|
||||
return uw::_URC_FATAL_PHASE1_ERROR;
|
||||
}
|
||||
let eh_action = match find_eh_action(context) {
|
||||
Ok(action) => action,
|
||||
Err(_) => return uw::_URC_FATAL_PHASE1_ERROR,
|
||||
};
|
||||
if actions as i32 & uw::_UA_SEARCH_PHASE as i32 != 0 {
|
||||
match eh_action {
|
||||
EHAction::None |
|
||||
EHAction::Cleanup(_) => return uw::_URC_CONTINUE_UNWIND,
|
||||
EHAction::Catch(_) => return uw::_URC_HANDLER_FOUND,
|
||||
EHAction::Terminate => return uw::_URC_FATAL_PHASE1_ERROR,
|
||||
}
|
||||
} else {
|
||||
match eh_action {
|
||||
EHAction::None => return uw::_URC_CONTINUE_UNWIND,
|
||||
EHAction::Cleanup(lpad) |
|
||||
EHAction::Catch(lpad) => {
|
||||
uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0, exception_object as uintptr_t);
|
||||
uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0);
|
||||
uw::_Unwind_SetIP(context, lpad);
|
||||
return uw::_URC_INSTALL_CONTEXT;
|
||||
}
|
||||
EHAction::Terminate => return uw::_URC_FATAL_PHASE2_ERROR,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn find_eh_action(context: *mut uw::_Unwind_Context)
|
||||
-> Result<EHAction, ()>
|
||||
{
|
||||
let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8;
|
||||
let func = uw::_Unwind_GetRegionStart(context);
|
||||
let ip = uw::_Unwind_GetIP(context);
|
||||
Ok(dwarf::find_eh_action(lsda, func, ip, [].as_c_slice()))
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#![feature(lang_items, panic_unwind, libc, unwind_attributes)]
|
||||
#![no_std]
|
||||
|
||||
extern crate cslice;
|
||||
extern crate unwind;
|
||||
extern crate libc;
|
||||
|
||||
pub mod dwarf;
|
||||
// pub mod eh_rust;
|
|
@ -8,6 +8,6 @@ name = "logger_artiq"
|
|||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
log = { version = "0.3", default-features = false, features = [] }
|
||||
log_buffer = { version = "1.2", git = "https://github.com/whitequark/rust-log_buffer", rev = "rust-1.25" }
|
||||
log = { version = "0.4", default-features = false }
|
||||
log_buffer = { version = "1.2" }
|
||||
board = { path = "../libboard" }
|
||||
|
|
|
@ -2,31 +2,29 @@
|
|||
|
||||
extern crate log;
|
||||
extern crate log_buffer;
|
||||
#[macro_use]
|
||||
extern crate board;
|
||||
|
||||
use core::ptr;
|
||||
use core::cell::{Cell, RefCell, Ref, RefMut};
|
||||
use core::cell::{Cell, RefCell, RefMut};
|
||||
use core::fmt::Write;
|
||||
use log::{Log, LogMetadata, LogRecord, LogLevelFilter, MaxLogLevelFilter};
|
||||
use log::{Log, LevelFilter};
|
||||
use log_buffer::LogBuffer;
|
||||
use board::{Console, clock};
|
||||
use board::clock;
|
||||
|
||||
pub struct LogBufferRef<'a> {
|
||||
buffer: RefMut<'a, LogBuffer<&'static mut [u8]>>,
|
||||
filter: Ref<'a, MaxLogLevelFilter>,
|
||||
old_log_level: LogLevelFilter
|
||||
old_log_level: LevelFilter
|
||||
}
|
||||
|
||||
impl<'a> LogBufferRef<'a> {
|
||||
fn new(buffer: RefMut<'a, LogBuffer<&'static mut [u8]>>,
|
||||
filter: Ref<'a, MaxLogLevelFilter>) -> LogBufferRef<'a> {
|
||||
let old_log_level = filter.get();
|
||||
filter.set(LogLevelFilter::Off);
|
||||
LogBufferRef { buffer, filter, old_log_level }
|
||||
fn new(buffer: RefMut<'a, LogBuffer<&'static mut [u8]>>) -> LogBufferRef<'a> {
|
||||
let old_log_level = log::max_level();
|
||||
log::set_max_level(LevelFilter::Off);
|
||||
LogBufferRef { buffer, old_log_level }
|
||||
}
|
||||
|
||||
pub fn is_empty(&mut self) -> bool {
|
||||
self.buffer.extract().len() == 0
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.buffer.is_empty()
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
|
@ -40,14 +38,13 @@ impl<'a> LogBufferRef<'a> {
|
|||
|
||||
impl<'a> Drop for LogBufferRef<'a> {
|
||||
fn drop(&mut self) {
|
||||
self.filter.set(self.old_log_level)
|
||||
log::set_max_level(self.old_log_level)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BufferLogger {
|
||||
buffer: RefCell<LogBuffer<&'static mut [u8]>>,
|
||||
filter: RefCell<Option<MaxLogLevelFilter>>,
|
||||
uart_filter: Cell<LogLevelFilter>
|
||||
uart_filter: Cell<LevelFilter>
|
||||
}
|
||||
|
||||
static mut LOGGER: *const BufferLogger = 0 as *const _;
|
||||
|
@ -56,28 +53,18 @@ impl BufferLogger {
|
|||
pub fn new(buffer: &'static mut [u8]) -> BufferLogger {
|
||||
BufferLogger {
|
||||
buffer: RefCell::new(LogBuffer::new(buffer)),
|
||||
filter: RefCell::new(None),
|
||||
uart_filter: Cell::new(LogLevelFilter::Info),
|
||||
uart_filter: Cell::new(LevelFilter::Info),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register<F: FnOnce()>(&self, f: F) {
|
||||
// log::set_logger_raw captures a pointer to ourselves, so we must prevent
|
||||
// ourselves from being moved or dropped after that function is called (and
|
||||
// before log::shutdown_logger_raw is called).
|
||||
unsafe {
|
||||
log::set_logger_raw(|max_log_level| {
|
||||
max_log_level.set(LogLevelFilter::Info);
|
||||
*self.filter.borrow_mut() = Some(max_log_level);
|
||||
self as *const Log
|
||||
}).expect("global logger can only be initialized once");
|
||||
LOGGER = self;
|
||||
log::set_logger(&*LOGGER)
|
||||
.expect("global logger can only be initialized once");
|
||||
}
|
||||
log::set_max_level(LevelFilter::Info);
|
||||
f();
|
||||
log::shutdown_logger_raw().unwrap();
|
||||
unsafe {
|
||||
LOGGER = ptr::null();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with<R, F: FnOnce(&BufferLogger) -> R>(f: F) -> R {
|
||||
|
@ -85,34 +72,17 @@ impl BufferLogger {
|
|||
}
|
||||
|
||||
pub fn buffer<'a>(&'a self) -> Result<LogBufferRef<'a>, ()> {
|
||||
let filter = Ref::map(self.filter.borrow(), |f| f.as_ref().unwrap());
|
||||
self.buffer
|
||||
.try_borrow_mut()
|
||||
.map(|buffer| LogBufferRef::new(buffer, filter))
|
||||
.map(LogBufferRef::new)
|
||||
.map_err(|_| ())
|
||||
}
|
||||
|
||||
pub fn max_log_level(&self) -> LogLevelFilter {
|
||||
self.filter
|
||||
.borrow()
|
||||
.as_ref()
|
||||
.expect("register the logger before touching maximum log level")
|
||||
.get()
|
||||
}
|
||||
|
||||
pub fn set_max_log_level(&self, max_level: LogLevelFilter) {
|
||||
self.filter
|
||||
.borrow()
|
||||
.as_ref()
|
||||
.expect("register the logger before touching maximum log level")
|
||||
.set(max_level)
|
||||
}
|
||||
|
||||
pub fn uart_log_level(&self) -> LogLevelFilter {
|
||||
pub fn uart_log_level(&self) -> LevelFilter {
|
||||
self.uart_filter.get()
|
||||
}
|
||||
|
||||
pub fn set_uart_log_level(&self, max_level: LogLevelFilter) {
|
||||
pub fn set_uart_log_level(&self, max_level: LevelFilter) {
|
||||
self.uart_filter.set(max_level)
|
||||
}
|
||||
}
|
||||
|
@ -121,11 +91,11 @@ impl BufferLogger {
|
|||
unsafe impl Sync for BufferLogger {}
|
||||
|
||||
impl Log for BufferLogger {
|
||||
fn enabled(&self, _metadata: &LogMetadata) -> bool {
|
||||
fn enabled(&self, _metadata: &log::Metadata) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn log(&self, record: &LogRecord) {
|
||||
fn log(&self, record: &log::Record) {
|
||||
if self.enabled(record.metadata()) {
|
||||
let timestamp = clock::get_us();
|
||||
let seconds = timestamp / 1_000_000;
|
||||
|
@ -137,10 +107,12 @@ impl Log for BufferLogger {
|
|||
}
|
||||
|
||||
if record.level() <= self.uart_filter.get() {
|
||||
writeln!(Console,
|
||||
"[{:6}.{:06}s] {:>5}({}): {}", seconds, micros,
|
||||
record.level(), record.target(), record.args()).unwrap();
|
||||
println!("[{:6}.{:06}s] {:>5}({}): {}", seconds, micros,
|
||||
record.level(), record.target(), record.args());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&self) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,6 @@ path = "lib.rs"
|
|||
[dependencies]
|
||||
byteorder = { version = "1.0", default-features = false }
|
||||
cslice = { version = "0.3" }
|
||||
log = { version = "0.3", default-features = false, optional = true }
|
||||
log = { version = "0.4", default-features = false, optional = true }
|
||||
std_artiq = { path = "../libstd_artiq", features = ["alloc"] }
|
||||
dyld = { path = "../libdyld" }
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::vec::Vec;
|
|||
use std::io::{self, Read, Write};
|
||||
use {ReadExt, WriteExt};
|
||||
#[cfg(feature = "log")]
|
||||
use log::LogLevelFilter;
|
||||
use log;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Request {
|
||||
|
@ -10,9 +10,9 @@ pub enum Request {
|
|||
ClearLog,
|
||||
PullLog,
|
||||
#[cfg(feature = "log")]
|
||||
SetLogFilter(LogLevelFilter),
|
||||
SetLogFilter(log::LevelFilter),
|
||||
#[cfg(feature = "log")]
|
||||
SetUartLogFilter(LogLevelFilter),
|
||||
SetUartLogFilter(log::LevelFilter),
|
||||
|
||||
Hotswap(Vec<u8>),
|
||||
Reboot,
|
||||
|
@ -29,14 +29,14 @@ pub enum Reply<'a> {
|
|||
impl Request {
|
||||
pub fn read_from(reader: &mut Read) -> io::Result<Request> {
|
||||
#[cfg(feature = "log")]
|
||||
fn read_log_level_filter(reader: &mut Read) -> io::Result<LogLevelFilter> {
|
||||
fn read_log_level_filter(reader: &mut Read) -> io::Result<log::LevelFilter> {
|
||||
Ok(match reader.read_u8()? {
|
||||
0 => LogLevelFilter::Off,
|
||||
1 => LogLevelFilter::Error,
|
||||
2 => LogLevelFilter::Warn,
|
||||
3 => LogLevelFilter::Info,
|
||||
4 => LogLevelFilter::Debug,
|
||||
5 => LogLevelFilter::Trace,
|
||||
0 => log::LevelFilter::Off,
|
||||
1 => log::LevelFilter::Error,
|
||||
2 => log::LevelFilter::Warn,
|
||||
3 => log::LevelFilter::Info,
|
||||
4 => log::LevelFilter::Debug,
|
||||
5 => log::LevelFilter::Trace,
|
||||
_ => return Err(io::Error::new(io::ErrorKind::InvalidData,
|
||||
"invalid log level"))
|
||||
})
|
||||
|
|
|
@ -1,19 +1,17 @@
|
|||
#![feature(lang_items, asm, alloc, needs_panic_runtime,
|
||||
unicode, raw, int_error_internals, try_from, macro_reexport,
|
||||
#![feature(lang_items, asm, alloc, needs_panic_runtime, use_extern_macros,
|
||||
unicode, raw, int_error_internals, try_from,
|
||||
allow_internal_unstable, stmt_expr_attributes, str_internals)]
|
||||
#![no_std]
|
||||
#![needs_panic_runtime]
|
||||
|
||||
extern crate std_unicode;
|
||||
#[macro_use]
|
||||
#[macro_reexport(vec, format)]
|
||||
extern crate alloc;
|
||||
|
||||
pub use core::{any, cell, clone, cmp, convert, default, hash, iter, marker, mem, num,
|
||||
ops, option, ptr, result, sync,
|
||||
char, i16, i32, i64, i8, isize, u16, u32, u64, u8, usize, f32, f64};
|
||||
pub use alloc::{arc, rc, raw_vec};
|
||||
pub use alloc::{binary_heap, borrow, boxed, btree_map, btree_set, fmt, linked_list, slice,
|
||||
pub use alloc::{binary_heap, borrow, boxed, btree_map, btree_set, fmt, format, linked_list, slice,
|
||||
str, string, vec, vec_deque};
|
||||
|
||||
pub mod prelude {
|
||||
|
|
|
@ -15,7 +15,8 @@ build_artiq = { path = "../libbuild_artiq" }
|
|||
[dependencies]
|
||||
byteorder = { version = "1.0", default-features = false }
|
||||
cslice = { version = "0.3" }
|
||||
log = { version = "0.3", default-features = false }
|
||||
log = { version = "0.4", default-features = false }
|
||||
managed = { version = "= 0.7.0", default-features = false, features = ["alloc", "map"] }
|
||||
alloc_list = { path = "../liballoc_list" }
|
||||
std_artiq = { path = "../libstd_artiq", features = ["alloc", "io_error_alloc"] }
|
||||
logger_artiq = { path = "../liblogger_artiq" }
|
||||
|
@ -25,19 +26,14 @@ proto = { path = "../libproto", features = ["log"] }
|
|||
amp = { path = "../libamp" }
|
||||
drtioaux = { path = "../libdrtioaux" }
|
||||
|
||||
[dependencies.compiler_builtins]
|
||||
git = "https://github.com/rust-lang-nursery/compiler-builtins"
|
||||
rev = "631b568"
|
||||
features = ["mem"]
|
||||
|
||||
[dependencies.fringe]
|
||||
git = "https://github.com/m-labs/libfringe"
|
||||
rev = "bd23494"
|
||||
rev = "b8a6d8f"
|
||||
default-features = false
|
||||
features = ["alloc"]
|
||||
|
||||
[dependencies.smoltcp]
|
||||
git = "https://github.com/m-labs/smoltcp"
|
||||
rev = "181083f"
|
||||
rev = "2139686" # NB: also change in libboard_misoc/Cargo.toml
|
||||
default-features = false
|
||||
features = ["alloc", "log", "proto-ipv4", "socket-tcp"]
|
||||
features = ["rust-1.28", "alloc", "log", "proto-ipv4", "socket-tcp"]
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use core::{slice, fmt};
|
||||
use smoltcp::Result;
|
||||
use smoltcp::time::Instant;
|
||||
use smoltcp::phy::{self, DeviceCapabilities, Device};
|
||||
|
||||
use board::{csr, mem};
|
||||
|
@ -77,7 +78,7 @@ impl<'a> Device<'a> for EthernetDevice {
|
|||
pub struct EthernetRxSlot(usize);
|
||||
|
||||
impl phy::RxToken for EthernetRxSlot {
|
||||
fn consume<R, F>(self, _timestamp: u64, f: F) -> Result<R>
|
||||
fn consume<R, F>(self, _timestamp: Instant, f: F) -> Result<R>
|
||||
where F: FnOnce(&[u8]) -> Result<R>
|
||||
{
|
||||
unsafe {
|
||||
|
@ -92,7 +93,7 @@ impl phy::RxToken for EthernetRxSlot {
|
|||
pub struct EthernetTxSlot(usize);
|
||||
|
||||
impl phy::TxToken for EthernetTxSlot {
|
||||
fn consume<R, F>(self, _timestamp: u64, length: usize, f: F) -> Result<R>
|
||||
fn consume<R, F>(self, _timestamp: Instant, length: usize, f: F) -> Result<R>
|
||||
where F: FnOnce(&mut [u8]) -> Result<R>
|
||||
{
|
||||
debug_assert!(length < SLOT_SIZE);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#![no_std]
|
||||
#![feature(compiler_builtins_lib, lang_items, alloc, global_allocator)]
|
||||
#![feature(lang_items, alloc, panic_implementation, panic_info_message)]
|
||||
|
||||
extern crate compiler_builtins;
|
||||
extern crate alloc;
|
||||
extern crate cslice;
|
||||
#[macro_use]
|
||||
|
@ -24,7 +23,7 @@ extern crate drtioaux;
|
|||
|
||||
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr};
|
||||
|
||||
use board::config;
|
||||
use board::{config, irq, boot, clock};
|
||||
use proto::{mgmt_proto, analyzer_proto, moninj_proto, rpc_proto, session_proto, kernel_proto};
|
||||
use amp::{mailbox, rpc_queue};
|
||||
|
||||
|
@ -97,18 +96,18 @@ fn startup() {
|
|||
let net_device = unsafe { ethmac::EthernetDevice::new() };
|
||||
|
||||
let net_device = {
|
||||
use smoltcp::time::Instant;
|
||||
use smoltcp::wire::PrettyPrinter;
|
||||
use smoltcp::wire::EthernetFrame;
|
||||
|
||||
fn net_trace_writer(timestamp: u64, printer: PrettyPrinter<EthernetFrame<&[u8]>>) {
|
||||
let seconds = timestamp / 1000;
|
||||
let micros = timestamp % 1000 * 1000;
|
||||
print!("\x1b[37m[{:6}.{:06}s]\n{}\x1b[0m\n", seconds, micros, printer)
|
||||
fn net_trace_writer(timestamp: Instant, printer: PrettyPrinter<EthernetFrame<&[u8]>>) {
|
||||
print!("\x1b[37m[{:6}.{:03}s]\n{}\x1b[0m\n",
|
||||
timestamp.secs(), timestamp.millis(), printer)
|
||||
}
|
||||
|
||||
fn net_trace_silent(_timestamp: u64, _printer: PrettyPrinter<EthernetFrame<&[u8]>>) {}
|
||||
fn net_trace_silent(_timestamp: Instant, _printer: PrettyPrinter<EthernetFrame<&[u8]>>) {}
|
||||
|
||||
let net_trace_fn: fn(u64, PrettyPrinter<EthernetFrame<&[u8]>>);
|
||||
let net_trace_fn: fn(Instant, PrettyPrinter<EthernetFrame<&[u8]>>);
|
||||
match config::read_str("net_trace", |r| r.map(|s| s == "1")) {
|
||||
Ok(true) => net_trace_fn = net_trace_writer,
|
||||
_ => net_trace_fn = net_trace_silent
|
||||
|
@ -135,26 +134,22 @@ fn startup() {
|
|||
#[cfg(has_rtio_analyzer)]
|
||||
io.spawn(4096, analyzer::thread);
|
||||
|
||||
match config::read_str("log_level", |r| r?.parse()) {
|
||||
Err(()) => (),
|
||||
Ok(log_level_filter) => {
|
||||
match config::read_str("log_level", |r| r.map(|s| s.parse())) {
|
||||
Ok(Ok(log_level_filter)) => {
|
||||
info!("log level set to {} by `log_level` config key",
|
||||
log_level_filter);
|
||||
logger_artiq::BufferLogger::with(|logger|
|
||||
logger.set_max_log_level(log_level_filter));
|
||||
log::set_max_level(log_level_filter);
|
||||
}
|
||||
_ => info!("log level set to INFO by default")
|
||||
}
|
||||
|
||||
match config::read_str("uart_log_level", |r| r?.parse()) {
|
||||
Err(()) => {
|
||||
info!("UART log level set to INFO by default");
|
||||
},
|
||||
Ok(uart_log_level_filter) => {
|
||||
match config::read_str("uart_log_level", |r| r.map(|s| s.parse())) {
|
||||
Ok(Ok(uart_log_level_filter)) => {
|
||||
info!("UART log level set to {} by `uart_log_level` config key",
|
||||
uart_log_level_filter);
|
||||
logger_artiq::BufferLogger::with(|logger|
|
||||
logger.set_uart_log_level(uart_log_level_filter));
|
||||
}
|
||||
_ => info!("UART log level set to INFO by default")
|
||||
}
|
||||
|
||||
loop {
|
||||
|
@ -163,7 +158,8 @@ fn startup() {
|
|||
{
|
||||
let sockets = &mut *scheduler.sockets().borrow_mut();
|
||||
loop {
|
||||
match interface.poll(sockets, board::clock::get_ms()) {
|
||||
let timestamp = smoltcp::time::Instant::from_millis(clock::get_ms() as i64);
|
||||
match interface.poll(sockets, timestamp) {
|
||||
Ok(true) => (),
|
||||
Ok(false) => break,
|
||||
Err(smoltcp::Error::Unrecognized) => (),
|
||||
|
@ -205,23 +201,42 @@ pub extern fn abort() {
|
|||
loop {}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[lang = "panic_fmt"]
|
||||
pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, line: u32) -> ! {
|
||||
println!("panic at {}:{}: {}", file, line, args);
|
||||
#[no_mangle] // https://github.com/rust-lang/rust/issues/{38281,51647}
|
||||
#[lang = "oom"] // https://github.com/rust-lang/rust/issues/51540
|
||||
pub fn oom(layout: core::alloc::Layout) -> ! {
|
||||
panic!("heap view: {}\ncannot allocate layout: {:?}", unsafe { &ALLOC }, layout)
|
||||
}
|
||||
|
||||
#[no_mangle] // https://github.com/rust-lang/rust/issues/{38281,51647}
|
||||
#[panic_implementation]
|
||||
pub fn panic_impl(info: &core::panic::PanicInfo) -> ! {
|
||||
irq::set_ie(false);
|
||||
|
||||
if let Some(location) = info.location() {
|
||||
print!("panic at {}:{}:{}", location.file(), location.line(), location.column());
|
||||
} else {
|
||||
print!("panic at unknown location");
|
||||
}
|
||||
if let Some(message) = info.message() {
|
||||
println!("{}", message);
|
||||
} else {
|
||||
println!("");
|
||||
}
|
||||
|
||||
println!("backtrace for software version {}:",
|
||||
include_str!(concat!(env!("OUT_DIR"), "/git-describe")));
|
||||
let _ = backtrace_artiq::backtrace(|ip| {
|
||||
println!("{:#08x}", ip);
|
||||
// Backtrace gives us the return address, i.e. the address after the delay slot,
|
||||
// but we're interested in the call instruction.
|
||||
println!("{:#08x}", ip - 2 * 4);
|
||||
});
|
||||
|
||||
if config::read_str("panic_reboot", |r| r == Ok("1")) {
|
||||
println!("rebooting...");
|
||||
unsafe { board::boot::reboot() }
|
||||
if config::read_str("panic_reset", |r| r == Ok("1")) {
|
||||
println!("restarting...");
|
||||
unsafe { boot::reboot() }
|
||||
} else {
|
||||
println!("halting.");
|
||||
println!("use `artiq_coreconfig write -s panic_reboot 1` to reboot instead");
|
||||
println!("use `artiq_coreconfig write -s panic_reset 1` to restart instead");
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use log::{self, LevelFilter};
|
||||
|
||||
use std::io::{self, Read, Write};
|
||||
use log::LogLevelFilter;
|
||||
use logger_artiq::BufferLogger;
|
||||
use sched::Io;
|
||||
use sched::{TcpListener, TcpStream};
|
||||
|
@ -30,8 +31,7 @@ fn worker(io: &Io, stream: &mut TcpStream) -> io::Result<()> {
|
|||
let mut buffer = io.until_ok(|| logger.buffer())?;
|
||||
Reply::LogContent(buffer.extract()).write_to(stream)
|
||||
})?;
|
||||
},
|
||||
|
||||
}
|
||||
Request::ClearLog => {
|
||||
BufferLogger::with(|logger| -> io::Result<()> {
|
||||
let mut buffer = io.until_ok(|| logger.buffer())?;
|
||||
|
@ -39,21 +39,20 @@ fn worker(io: &Io, stream: &mut TcpStream) -> io::Result<()> {
|
|||
})?;
|
||||
|
||||
Reply::Success.write_to(stream)?;
|
||||
},
|
||||
|
||||
}
|
||||
Request::PullLog => {
|
||||
BufferLogger::with(|logger| -> io::Result<()> {
|
||||
loop {
|
||||
// Do this *before* acquiring the buffer, since that sets the log level
|
||||
// to OFF.
|
||||
let log_level = logger.max_log_level();
|
||||
let log_level = log::max_level();
|
||||
|
||||
let mut buffer = io.until_ok(|| logger.buffer())?;
|
||||
if buffer.is_empty() { continue }
|
||||
|
||||
stream.write_string(buffer.extract())?;
|
||||
|
||||
if log_level == LogLevelFilter::Trace {
|
||||
if log_level == LevelFilter::Trace {
|
||||
// Hold exclusive access over the logger until we get positive
|
||||
// acknowledgement; otherwise we get an infinite loop of network
|
||||
// trace messages being transmitted and causing more network
|
||||
|
@ -69,21 +68,18 @@ fn worker(io: &Io, stream: &mut TcpStream) -> io::Result<()> {
|
|||
buffer.clear();
|
||||
}
|
||||
})?;
|
||||
},
|
||||
|
||||
}
|
||||
Request::SetLogFilter(level) => {
|
||||
info!("changing log level to {}", level);
|
||||
BufferLogger::with(|logger|
|
||||
logger.set_max_log_level(level));
|
||||
log::set_max_level(level);
|
||||
Reply::Success.write_to(stream)?;
|
||||
},
|
||||
|
||||
}
|
||||
Request::SetUartLogFilter(level) => {
|
||||
info!("changing UART log level to {}", level);
|
||||
BufferLogger::with(|logger|
|
||||
logger.set_uart_log_level(level));
|
||||
Reply::Success.write_to(stream)?;
|
||||
},
|
||||
}
|
||||
|
||||
Request::Hotswap(firmware) => {
|
||||
Reply::RebootImminent.write_to(stream)?;
|
||||
|
|
|
@ -8,6 +8,8 @@ use std::io::{Read, Write, Result, Error, ErrorKind};
|
|||
use fringe::OwnedStack;
|
||||
use fringe::generator::{Generator, Yielder, State as GeneratorState};
|
||||
|
||||
use smoltcp::time::Duration;
|
||||
use smoltcp::Error as NetworkError;
|
||||
use smoltcp::wire::IpEndpoint;
|
||||
use smoltcp::socket::{SocketHandle, SocketRef};
|
||||
|
||||
|
@ -421,19 +423,19 @@ impl<'a> TcpStream<'a> {
|
|||
}
|
||||
|
||||
pub fn timeout(&self) -> Option<u64> {
|
||||
self.with_lower(|s| s.timeout())
|
||||
self.with_lower(|s| s.timeout().as_ref().map(Duration::millis))
|
||||
}
|
||||
|
||||
pub fn set_timeout(&self, value: Option<u64>) {
|
||||
self.with_lower(|mut s| s.set_timeout(value))
|
||||
self.with_lower(|mut s| s.set_timeout(value.map(Duration::from_millis)))
|
||||
}
|
||||
|
||||
pub fn keep_alive(&self) -> Option<u64> {
|
||||
self.with_lower(|s| s.keep_alive())
|
||||
self.with_lower(|s| s.keep_alive().as_ref().map(Duration::millis))
|
||||
}
|
||||
|
||||
pub fn set_keep_alive(&self, value: Option<u64>) {
|
||||
self.with_lower(|mut s| s.set_keep_alive(value))
|
||||
self.with_lower(|mut s| s.set_keep_alive(value.map(Duration::from_millis)))
|
||||
}
|
||||
|
||||
pub fn close(&self) -> Result<()> {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(compiler_builtins_lib, lang_items)]
|
||||
#![feature(never_type, panic_implementation, panic_info_message)]
|
||||
#![no_std]
|
||||
|
||||
extern crate compiler_builtins;
|
||||
|
@ -241,10 +241,19 @@ pub extern fn abort() {
|
|||
panic!("aborted")
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[lang = "panic_fmt"]
|
||||
pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, line: u32) -> ! {
|
||||
println!("panic at {}:{}: {}", file, line, args);
|
||||
#[no_mangle] // https://github.com/rust-lang/rust/issues/{38281,51647}
|
||||
#[panic_implementation]
|
||||
pub fn panic_fmt(info: &core::panic::PanicInfo) -> ! {
|
||||
if let Some(location) = info.location() {
|
||||
print!("panic at {}:{}:{}", location.file(), location.line(), location.column());
|
||||
} else {
|
||||
print!("panic at unknown location");
|
||||
}
|
||||
if let Some(message) = info.message() {
|
||||
println!(": {}", message);
|
||||
} else {
|
||||
println!("");
|
||||
}
|
||||
loop {}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,345 @@
|
|||
#![feature(never_type, panic_implementation, panic_info_message)]
|
||||
#![no_std]
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
#[macro_use]
|
||||
extern crate board_misoc;
|
||||
extern crate board_artiq;
|
||||
|
||||
use board_misoc::{csr, ident, clock, uart_logger};
|
||||
use board_artiq::{i2c, spi, si5324, drtioaux};
|
||||
#[cfg(has_serwb_phy_amc)]
|
||||
use board_artiq::serwb;
|
||||
#[cfg(has_hmc830_7043)]
|
||||
use board_artiq::hmc830_7043;
|
||||
|
||||
fn drtio_reset(reset: bool) {
|
||||
unsafe {
|
||||
(csr::DRTIO[0].reset_write)(if reset { 1 } else { 0 });
|
||||
}
|
||||
}
|
||||
|
||||
fn drtio_reset_phy(reset: bool) {
|
||||
unsafe {
|
||||
(csr::DRTIO[0].reset_phy_write)(if reset { 1 } else { 0 });
|
||||
}
|
||||
}
|
||||
|
||||
fn drtio_tsc_loaded() -> bool {
|
||||
unsafe {
|
||||
let tsc_loaded = (csr::DRTIO[0].tsc_loaded_read)() == 1;
|
||||
if tsc_loaded {
|
||||
(csr::DRTIO[0].tsc_loaded_write)(1);
|
||||
}
|
||||
tsc_loaded
|
||||
}
|
||||
}
|
||||
|
||||
fn process_aux_packet(packet: drtioaux::Packet) -> Result<(), drtioaux::Error<!>> {
|
||||
// In the code below, *_chan_sel_write takes an u8 if there are fewer than 256 channels,
|
||||
// and u16 otherwise; hence the `as _` conversion.
|
||||
match packet {
|
||||
drtioaux::Packet::EchoRequest =>
|
||||
drtioaux::send_link(0, &drtioaux::Packet::EchoReply),
|
||||
drtioaux::Packet::ResetRequest { phy } => {
|
||||
if phy {
|
||||
drtio_reset_phy(true);
|
||||
drtio_reset_phy(false);
|
||||
} else {
|
||||
drtio_reset(true);
|
||||
drtio_reset(false);
|
||||
}
|
||||
drtioaux::send_link(0, &drtioaux::Packet::ResetAck)
|
||||
},
|
||||
|
||||
drtioaux::Packet::RtioErrorRequest => {
|
||||
let errors;
|
||||
unsafe {
|
||||
errors = (csr::DRTIO[0].rtio_error_read)();
|
||||
}
|
||||
if errors & 1 != 0 {
|
||||
let channel;
|
||||
unsafe {
|
||||
channel = (csr::DRTIO[0].sequence_error_channel_read)();
|
||||
(csr::DRTIO[0].rtio_error_write)(1);
|
||||
}
|
||||
drtioaux::send_link(0,
|
||||
&drtioaux::Packet::RtioErrorSequenceErrorReply { channel })
|
||||
} else if errors & 2 != 0 {
|
||||
let channel;
|
||||
unsafe {
|
||||
channel = (csr::DRTIO[0].collision_channel_read)();
|
||||
(csr::DRTIO[0].rtio_error_write)(2);
|
||||
}
|
||||
drtioaux::send_link(0,
|
||||
&drtioaux::Packet::RtioErrorCollisionReply { channel })
|
||||
} else if errors & 4 != 0 {
|
||||
let channel;
|
||||
unsafe {
|
||||
channel = (csr::DRTIO[0].busy_channel_read)();
|
||||
(csr::DRTIO[0].rtio_error_write)(4);
|
||||
}
|
||||
drtioaux::send_link(0,
|
||||
&drtioaux::Packet::RtioErrorBusyReply { channel })
|
||||
}
|
||||
else {
|
||||
drtioaux::send_link(0, &drtioaux::Packet::RtioNoErrorReply)
|
||||
}
|
||||
}
|
||||
|
||||
drtioaux::Packet::MonitorRequest { channel, probe } => {
|
||||
let value;
|
||||
#[cfg(has_rtio_moninj)]
|
||||
unsafe {
|
||||
csr::rtio_moninj::mon_chan_sel_write(channel as _);
|
||||
csr::rtio_moninj::mon_probe_sel_write(probe);
|
||||
csr::rtio_moninj::mon_value_update_write(1);
|
||||
value = csr::rtio_moninj::mon_value_read();
|
||||
}
|
||||
#[cfg(not(has_rtio_moninj))]
|
||||
{
|
||||
value = 0;
|
||||
}
|
||||
let reply = drtioaux::Packet::MonitorReply { value: value as u32 };
|
||||
drtioaux::send_link(0, &reply)
|
||||
},
|
||||
drtioaux::Packet::InjectionRequest { channel, overrd, value } => {
|
||||
#[cfg(has_rtio_moninj)]
|
||||
unsafe {
|
||||
csr::rtio_moninj::inj_chan_sel_write(channel as _);
|
||||
csr::rtio_moninj::inj_override_sel_write(overrd);
|
||||
csr::rtio_moninj::inj_value_write(value);
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
drtioaux::Packet::InjectionStatusRequest { channel, overrd } => {
|
||||
let value;
|
||||
#[cfg(has_rtio_moninj)]
|
||||
unsafe {
|
||||
csr::rtio_moninj::inj_chan_sel_write(channel as _);
|
||||
csr::rtio_moninj::inj_override_sel_write(overrd);
|
||||
value = csr::rtio_moninj::inj_value_read();
|
||||
}
|
||||
#[cfg(not(has_rtio_moninj))]
|
||||
{
|
||||
value = 0;
|
||||
}
|
||||
drtioaux::send_link(0, &drtioaux::Packet::InjectionStatusReply { value: value })
|
||||
},
|
||||
|
||||
drtioaux::Packet::I2cStartRequest { busno } => {
|
||||
let succeeded = i2c::start(busno).is_ok();
|
||||
drtioaux::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
|
||||
}
|
||||
drtioaux::Packet::I2cRestartRequest { busno } => {
|
||||
let succeeded = i2c::restart(busno).is_ok();
|
||||
drtioaux::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
|
||||
}
|
||||
drtioaux::Packet::I2cStopRequest { busno } => {
|
||||
let succeeded = i2c::stop(busno).is_ok();
|
||||
drtioaux::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
|
||||
}
|
||||
drtioaux::Packet::I2cWriteRequest { busno, data } => {
|
||||
match i2c::write(busno, data) {
|
||||
Ok(ack) => drtioaux::send_link(0,
|
||||
&drtioaux::Packet::I2cWriteReply { succeeded: true, ack: ack }),
|
||||
Err(_) => drtioaux::send_link(0,
|
||||
&drtioaux::Packet::I2cWriteReply { succeeded: false, ack: false })
|
||||
}
|
||||
}
|
||||
drtioaux::Packet::I2cReadRequest { busno, ack } => {
|
||||
match i2c::read(busno, ack) {
|
||||
Ok(data) => drtioaux::send_link(0,
|
||||
&drtioaux::Packet::I2cReadReply { succeeded: true, data: data }),
|
||||
Err(_) => drtioaux::send_link(0,
|
||||
&drtioaux::Packet::I2cReadReply { succeeded: false, data: 0xff })
|
||||
}
|
||||
}
|
||||
|
||||
drtioaux::Packet::SpiSetConfigRequest { busno, flags, length, div, cs } => {
|
||||
let succeeded = spi::set_config(busno, flags, length, div, cs).is_ok();
|
||||
drtioaux::send_link(0,
|
||||
&drtioaux::Packet::SpiBasicReply { succeeded: succeeded })
|
||||
},
|
||||
drtioaux::Packet::SpiWriteRequest { busno, data } => {
|
||||
let succeeded = spi::write(busno, data).is_ok();
|
||||
drtioaux::send_link(0,
|
||||
&drtioaux::Packet::SpiBasicReply { succeeded: succeeded })
|
||||
}
|
||||
drtioaux::Packet::SpiReadRequest { busno } => {
|
||||
match spi::read(busno) {
|
||||
Ok(data) => drtioaux::send_link(0,
|
||||
&drtioaux::Packet::SpiReadReply { succeeded: true, data: data }),
|
||||
Err(_) => drtioaux::send_link(0,
|
||||
&drtioaux::Packet::SpiReadReply { succeeded: false, data: 0 })
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
warn!("received unexpected aux packet");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn process_aux_packets() {
|
||||
let result =
|
||||
drtioaux::recv_link(0).and_then(|packet| {
|
||||
if let Some(packet) = packet {
|
||||
process_aux_packet(packet)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
});
|
||||
match result {
|
||||
Ok(()) => (),
|
||||
Err(e) => warn!("aux packet error ({})", e)
|
||||
}
|
||||
}
|
||||
|
||||
fn process_errors() {
|
||||
let errors;
|
||||
unsafe {
|
||||
errors = (csr::DRTIO[0].protocol_error_read)();
|
||||
}
|
||||
if errors & 1 != 0 {
|
||||
error!("received packet of an unknown type");
|
||||
}
|
||||
if errors & 2 != 0 {
|
||||
error!("received truncated packet");
|
||||
}
|
||||
if errors & 4 != 0 {
|
||||
let channel;
|
||||
let timestamp_event;
|
||||
let timestamp_counter;
|
||||
unsafe {
|
||||
channel = (csr::DRTIO[0].underflow_channel_read)();
|
||||
timestamp_event = (csr::DRTIO[0].underflow_timestamp_event_read)() as i64;
|
||||
timestamp_counter = (csr::DRTIO[0].underflow_timestamp_counter_read)() as i64;
|
||||
}
|
||||
error!("write underflow, channel={}, timestamp={}, counter={}, slack={}",
|
||||
channel, timestamp_event, timestamp_counter, timestamp_event-timestamp_counter);
|
||||
}
|
||||
if errors & 8 != 0 {
|
||||
error!("write overflow");
|
||||
}
|
||||
unsafe {
|
||||
(csr::DRTIO[0].protocol_error_write)(errors);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(rtio_frequency = "150.0")]
|
||||
const SI5324_SETTINGS: si5324::FrequencySettings
|
||||
= si5324::FrequencySettings {
|
||||
n1_hs : 6,
|
||||
nc1_ls : 6,
|
||||
n2_hs : 10,
|
||||
n2_ls : 270,
|
||||
n31 : 75,
|
||||
n32 : 75,
|
||||
bwsel : 4,
|
||||
crystal_ref: true
|
||||
};
|
||||
|
||||
fn drtio_link_rx_up() -> bool {
|
||||
unsafe {
|
||||
(csr::DRTIO[0].rx_up_read)() == 1
|
||||
}
|
||||
}
|
||||
|
||||
const SIPHASER_PHASE: u16 = 32;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn main() -> i32 {
|
||||
clock::init();
|
||||
uart_logger::ConsoleLogger::register();
|
||||
|
||||
info!("ARTIQ satellite manager starting...");
|
||||
info!("software ident {}", csr::CONFIG_IDENTIFIER_STR);
|
||||
info!("gateware ident {}", ident::read(&mut [0; 64]));
|
||||
|
||||
#[cfg(has_slave_fpga_cfg)]
|
||||
board_artiq::slave_fpga::load().expect("cannot load RTM FPGA gateware");
|
||||
#[cfg(has_serwb_phy_amc)]
|
||||
serwb::wait_init();
|
||||
|
||||
i2c::init();
|
||||
si5324::setup(&SI5324_SETTINGS, si5324::Input::Ckin1).expect("cannot initialize Si5324");
|
||||
#[cfg(has_hmc830_7043)]
|
||||
/* must be the first SPI init because of HMC830 SPI mode selection */
|
||||
hmc830_7043::init().expect("cannot initialize HMC830/7043");
|
||||
unsafe {
|
||||
csr::drtio_transceiver::stable_clkin_write(1);
|
||||
}
|
||||
|
||||
#[cfg(has_ad9154)]
|
||||
{
|
||||
board_artiq::ad9154::jesd_unreset();
|
||||
board_artiq::ad9154::init();
|
||||
}
|
||||
#[cfg(has_allaki_atts)]
|
||||
board_artiq::hmc542::program_all(8/*=4dB*/);
|
||||
|
||||
loop {
|
||||
while !drtio_link_rx_up() {
|
||||
process_errors();
|
||||
}
|
||||
info!("link is up, switching to recovered clock");
|
||||
si5324::siphaser::select_recovered_clock(true).expect("failed to switch clocks");
|
||||
si5324::siphaser::calibrate_skew(SIPHASER_PHASE).expect("failed to calibrate skew");
|
||||
drtioaux::reset(0);
|
||||
drtio_reset(false);
|
||||
drtio_reset_phy(false);
|
||||
while drtio_link_rx_up() {
|
||||
process_errors();
|
||||
process_aux_packets();
|
||||
if drtio_tsc_loaded() {
|
||||
#[cfg(has_ad9154)]
|
||||
{
|
||||
if let Err(e) = board_artiq::jesd204sync::sysref_auto_rtio_align() {
|
||||
error!("failed to align SYSREF at FPGA: {}", e);
|
||||
}
|
||||
if let Err(e) = board_artiq::jesd204sync::sysref_auto_dac_align() {
|
||||
error!("failed to align SYSREF at DAC: {}", e);
|
||||
}
|
||||
}
|
||||
if let Err(e) = drtioaux::send_link(0, &drtioaux::Packet::TSCAck) {
|
||||
error!("aux packet error: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
drtio_reset_phy(true);
|
||||
drtio_reset(true);
|
||||
drtio_tsc_loaded();
|
||||
info!("link is down, switching to local crystal clock");
|
||||
si5324::siphaser::select_recovered_clock(false).expect("failed to switch clocks");
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn exception(vect: u32, _regs: *const u32, pc: u32, ea: u32) {
|
||||
panic!("exception {:?} at PC 0x{:x}, EA 0x{:x}", vect, pc, ea)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn abort() {
|
||||
println!("aborted");
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[no_mangle] // https://github.com/rust-lang/rust/issues/{38281,51647}
|
||||
#[panic_implementation]
|
||||
pub fn panic_fmt(info: &core::panic::PanicInfo) -> ! {
|
||||
if let Some(location) = info.location() {
|
||||
print!("panic at {}:{}:{}", location.file(), location.line(), location.column());
|
||||
} else {
|
||||
print!("panic at unknown location");
|
||||
}
|
||||
if let Some(message) = info.message() {
|
||||
println!(": {}", message);
|
||||
} else {
|
||||
println!("");
|
||||
}
|
||||
loop {}
|
||||
}
|
|
@ -43,7 +43,7 @@ class TransferTest(ExperimentCase):
|
|||
exp = self.create(_Transfer)
|
||||
host_to_device_rate = exp.host_to_device()
|
||||
print(host_to_device_rate, "B/s")
|
||||
self.assertGreater(host_to_device_rate, 2e6)
|
||||
self.assertGreater(host_to_device_rate, 1.8e6)
|
||||
|
||||
@unittest.skipUnless(artiq_low_latency,
|
||||
"timings are dependent on CPU load and network conditions")
|
||||
|
@ -51,4 +51,32 @@ class TransferTest(ExperimentCase):
|
|||
exp = self.create(_Transfer)
|
||||
device_to_host_rate = exp.device_to_host()
|
||||
print(device_to_host_rate, "B/s")
|
||||
self.assertGreater(device_to_host_rate, 2e6)
|
||||
self.assertGreater(device_to_host_rate, 1.8e6)
|
||||
|
||||
|
||||
class _KernelOverhead(EnvExperiment):
|
||||
def build(self):
|
||||
self.setattr_device("core")
|
||||
|
||||
def kernel_overhead(self):
|
||||
n = 100
|
||||
t0 = time.monotonic()
|
||||
for _ in range(n):
|
||||
self.dummy_kernel()
|
||||
t1 = time.monotonic()
|
||||
return (t1-t0)/n
|
||||
|
||||
@kernel
|
||||
def dummy_kernel(self):
|
||||
pass
|
||||
|
||||
|
||||
class KernelOverheadTest(ExperimentCase):
|
||||
@unittest.skipUnless(artiq_low_latency,
|
||||
"timings are dependent on CPU load and network conditions")
|
||||
def test_kernel_overhead(self):
|
||||
exp = self.create(_KernelOverhead)
|
||||
kernel_overhead = exp.kernel_overhead()
|
||||
print(kernel_overhead, "s")
|
||||
self.assertGreater(kernel_overhead, 0.001)
|
||||
self.assertLess(kernel_overhead, 0.5)
|
||||
|
|
|
@ -50,12 +50,17 @@ mod cslice {
|
|||
}
|
||||
}
|
||||
|
||||
#[path = "../../firmware/ksupport/eh.rs"]
|
||||
pub mod eh;
|
||||
#[path = "."]
|
||||
pub mod eh {
|
||||
#[path = "../../firmware/libeh/dwarf.rs"]
|
||||
pub mod dwarf;
|
||||
}
|
||||
#[path = "../../firmware/ksupport/eh_artiq.rs"]
|
||||
pub mod eh_artiq;
|
||||
|
||||
use std::{str, process};
|
||||
|
||||
fn terminate(exception: &eh::Exception, mut _backtrace: &mut [usize]) -> ! {
|
||||
fn terminate(exception: &eh_artiq::Exception, mut _backtrace: &mut [usize]) -> ! {
|
||||
println!("Uncaught {}: {} ({}, {}, {})",
|
||||
str::from_utf8(exception.name.as_ref()).unwrap(),
|
||||
str::from_utf8(exception.message.as_ref()).unwrap(),
|
||||
|
|
|
@ -6,7 +6,7 @@ from artiq.experiment import *
|
|||
@kernel
|
||||
def entrypoint():
|
||||
a = [1,2]
|
||||
# CHECK-L: ${LINE:+2}: error: values cannot be mutated in-place
|
||||
# CHECK-L: ${LINE:+2}: error: lists cannot be mutated in-place
|
||||
# CHECK-L: ${LINE:+1}: note: try using `a = a + [3,4]`
|
||||
a += [3,4]
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ if os.name == "posix":
|
|||
support_build = os.path.join(root, "libartiq_support")
|
||||
if subprocess.call(["rustc", os.path.join(support_build, "lib.rs"),
|
||||
"--out-dir", support_build,
|
||||
"-Cpanic=abort", "-g"]) != 0:
|
||||
"-Cpanic=unwind", "-g"]) != 0:
|
||||
lit_config.fatal("Unable to build JIT support library")
|
||||
|
||||
support_lib = os.path.join(support_build, "libartiq_support.so")
|
||||
|
|
|
@ -19,8 +19,8 @@ requirements:
|
|||
- jesd204b 0.3
|
||||
- binutils-or1k-linux >=2.27
|
||||
- llvm-or1k 6.0.0
|
||||
- llvmlite-artiq 0.23.0.dev py35_2
|
||||
- rust-core-or1k 1.25.0 20
|
||||
- llvmlite-artiq 0.23.0.dev py35_4
|
||||
- rust-core-or1k 1.28.0 21
|
||||
- openocd 0.10.0 1
|
||||
- lit
|
||||
- outputcheck
|
||||
|
|
Loading…
Reference in New Issue