Exception handling working
This commit is contained in:
parent
faaf9e6ca0
commit
d2e1a57616
|
@ -35,6 +35,12 @@ version = "1.3.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.0.54"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7bbb73db36c1246e9034e307d0fba23f9a2e251faa47ade70c1bd252220c8311"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "0.1.10"
|
version = "0.1.10"
|
||||||
|
@ -76,6 +82,16 @@ version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7313c0d620d0cb4dbd9d019e461a4beb501071ff46ec0ab933efb4daa76d73e3"
|
checksum = "7313c0d620d0cb4dbd9d019e461a4beb501071ff46ec0ab933efb4daa76d73e3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dwarf"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"compiler_builtins",
|
||||||
|
"libc",
|
||||||
|
"unwind",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dyld"
|
name = "dyld"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -184,7 +200,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libasync"
|
name = "libasync"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#ec252b099cf67a51ba9daa72b3292db8c21ba1b8"
|
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#6195ad40c334a847cd01cd4adadf6b8f8d730908"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"embedded-hal",
|
"embedded-hal",
|
||||||
"libcortex_a9",
|
"libcortex_a9",
|
||||||
|
@ -196,7 +212,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libboard_zynq"
|
name = "libboard_zynq"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#ec252b099cf67a51ba9daa72b3292db8c21ba1b8"
|
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#6195ad40c334a847cd01cd4adadf6b8f8d730908"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit_field",
|
"bit_field",
|
||||||
"embedded-hal",
|
"embedded-hal",
|
||||||
|
@ -209,10 +225,14 @@ dependencies = [
|
||||||
"volatile-register",
|
"volatile-register",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libcortex_a9"
|
name = "libcortex_a9"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#ec252b099cf67a51ba9daa72b3292db8c21ba1b8"
|
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#6195ad40c334a847cd01cd4adadf6b8f8d730908"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit_field",
|
"bit_field",
|
||||||
"libregister",
|
"libregister",
|
||||||
|
@ -221,7 +241,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libregister"
|
name = "libregister"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#ec252b099cf67a51ba9daa72b3292db8c21ba1b8"
|
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#6195ad40c334a847cd01cd4adadf6b8f8d730908"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit_field",
|
"bit_field",
|
||||||
"vcell",
|
"vcell",
|
||||||
|
@ -231,7 +251,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libsupport_zynq"
|
name = "libsupport_zynq"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#ec252b099cf67a51ba9daa72b3292db8c21ba1b8"
|
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#6195ad40c334a847cd01cd4adadf6b8f8d730908"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"compiler_builtins",
|
"compiler_builtins",
|
||||||
"libboard_zynq",
|
"libboard_zynq",
|
||||||
|
@ -364,16 +384,19 @@ dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"core_io",
|
"core_io",
|
||||||
"cslice",
|
"cslice",
|
||||||
|
"dwarf",
|
||||||
"dyld",
|
"dyld",
|
||||||
"fatfs",
|
"fatfs",
|
||||||
"futures",
|
"futures",
|
||||||
"libasync",
|
"libasync",
|
||||||
"libboard_zynq",
|
"libboard_zynq",
|
||||||
|
"libc",
|
||||||
"libcortex_a9",
|
"libcortex_a9",
|
||||||
"libsupport_zynq",
|
"libsupport_zynq",
|
||||||
"log",
|
"log",
|
||||||
"num-derive",
|
"num-derive",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
|
"unwind",
|
||||||
"void",
|
"void",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -416,6 +439,16 @@ version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unwind"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"cfg-if",
|
||||||
|
"compiler_builtins",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vcell"
|
name = "vcell"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
|
"libc",
|
||||||
"libdyld",
|
"libdyld",
|
||||||
"libcoreio",
|
"libcoreio",
|
||||||
|
"libdwarf",
|
||||||
|
"libunwind",
|
||||||
"runtime",
|
"runtime",
|
||||||
"szl"
|
"szl"
|
||||||
]
|
]
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
"max-atomic-width": 32,
|
"max-atomic-width": 32,
|
||||||
"os": "none",
|
"os": "none",
|
||||||
"panic-strategy": "abort",
|
"panic-strategy": "abort",
|
||||||
|
"requires-uwtable": true,
|
||||||
|
"force-unwind-tables": "yes",
|
||||||
"relocation-model": "static",
|
"relocation-model": "static",
|
||||||
"target-c-int-width": "32",
|
"target-c-int-width": "32",
|
||||||
"target-endian": "little",
|
"target-endian": "little",
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
[package]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["pca006132 <john.lck40@gmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
|
@ -0,0 +1,7 @@
|
||||||
|
// Helper crate for dealing with libc dependencies, which only requires these
|
||||||
|
// definitions...
|
||||||
|
#![allow(non_camel_case_types)]
|
||||||
|
#![no_std]
|
||||||
|
pub type c_int = i32;
|
||||||
|
pub type uintptr_t = usize;
|
||||||
|
pub type c_void = core::ffi::c_void;
|
|
@ -0,0 +1,17 @@
|
||||||
|
[package]
|
||||||
|
# This package is orignally panic_unwind, but is adapted as a dwarf parser
|
||||||
|
authors = ["The Rust Project Developers"]
|
||||||
|
name = "dwarf"
|
||||||
|
version = "0.0.0"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
test = false
|
||||||
|
bench = false
|
||||||
|
doc = false
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libc = { path = "../libc" }
|
||||||
|
unwind = { path = "../libunwind" }
|
||||||
|
compiler_builtins = "0.1.0"
|
||||||
|
cfg-if = "0.1.8"
|
|
@ -0,0 +1,200 @@
|
||||||
|
//! Parsing of GCC-style Language-Specific Data Area (LSDA)
|
||||||
|
//! For details see:
|
||||||
|
//! http://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html
|
||||||
|
//! http://mentorembedded.github.io/cxx-abi/exceptions.pdf
|
||||||
|
//! http://www.airs.com/blog/archives/460
|
||||||
|
//! http://www.airs.com/blog/archives/464
|
||||||
|
//!
|
||||||
|
//! A reference implementation may be found in the GCC source tree
|
||||||
|
//! (`<root>/libgcc/unwind-c.c` as of this writing).
|
||||||
|
|
||||||
|
#![allow(non_upper_case_globals)]
|
||||||
|
#![allow(unused)]
|
||||||
|
|
||||||
|
use crate::DwarfReader;
|
||||||
|
use core::mem;
|
||||||
|
|
||||||
|
pub const DW_EH_PE_omit: u8 = 0xFF;
|
||||||
|
pub const DW_EH_PE_absptr: u8 = 0x00;
|
||||||
|
|
||||||
|
pub const DW_EH_PE_uleb128: u8 = 0x01;
|
||||||
|
pub const DW_EH_PE_udata2: u8 = 0x02;
|
||||||
|
pub const DW_EH_PE_udata4: u8 = 0x03;
|
||||||
|
pub const DW_EH_PE_udata8: u8 = 0x04;
|
||||||
|
pub const DW_EH_PE_sleb128: u8 = 0x09;
|
||||||
|
pub const DW_EH_PE_sdata2: u8 = 0x0A;
|
||||||
|
pub const DW_EH_PE_sdata4: u8 = 0x0B;
|
||||||
|
pub const DW_EH_PE_sdata8: u8 = 0x0C;
|
||||||
|
|
||||||
|
pub const DW_EH_PE_pcrel: u8 = 0x10;
|
||||||
|
pub const DW_EH_PE_textrel: u8 = 0x20;
|
||||||
|
pub const DW_EH_PE_datarel: u8 = 0x30;
|
||||||
|
pub const DW_EH_PE_funcrel: u8 = 0x40;
|
||||||
|
pub const DW_EH_PE_aligned: u8 = 0x50;
|
||||||
|
|
||||||
|
pub const DW_EH_PE_indirect: u8 = 0x80;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct EHContext<'a> {
|
||||||
|
pub ip: usize, // Current instruction pointer
|
||||||
|
pub func_start: usize, // Address of the current function
|
||||||
|
pub get_text_start: &'a dyn Fn() -> usize, // Get address of the code section
|
||||||
|
pub get_data_start: &'a dyn Fn() -> usize, // Get address of the data section
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum EHAction {
|
||||||
|
None,
|
||||||
|
Cleanup(usize),
|
||||||
|
Catch(usize),
|
||||||
|
Terminate,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const USING_SJLJ_EXCEPTIONS: bool = cfg!(all(target_os = "ios", target_arch = "arm"));
|
||||||
|
|
||||||
|
pub unsafe fn find_eh_action(
|
||||||
|
lsda: *const u8,
|
||||||
|
context: &EHContext<'_>,
|
||||||
|
foreign_exception: bool,
|
||||||
|
) -> Result<EHAction, ()> {
|
||||||
|
if lsda.is_null() {
|
||||||
|
return Ok(EHAction::None);
|
||||||
|
}
|
||||||
|
|
||||||
|
let func_start = context.func_start;
|
||||||
|
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 {
|
||||||
|
read_encoded_pointer(&mut reader, context, start_encoding)?
|
||||||
|
} else {
|
||||||
|
func_start
|
||||||
|
};
|
||||||
|
|
||||||
|
let ttype_encoding = reader.read::<u8>();
|
||||||
|
if ttype_encoding != DW_EH_PE_omit {
|
||||||
|
// Rust doesn't analyze exception types, so we don't care about the type table
|
||||||
|
reader.read_uleb128();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
let ip = context.ip;
|
||||||
|
|
||||||
|
if !USING_SJLJ_EXCEPTIONS {
|
||||||
|
while reader.ptr < action_table {
|
||||||
|
let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding)?;
|
||||||
|
let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding)?;
|
||||||
|
let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding)?;
|
||||||
|
let cs_action = reader.read_uleb128();
|
||||||
|
// Callsite table is sorted by cs_start, so if we've passed the ip, we
|
||||||
|
// may stop searching.
|
||||||
|
if ip < func_start + cs_start {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ip < func_start + cs_start + cs_len {
|
||||||
|
if cs_lpad == 0 {
|
||||||
|
return Ok(EHAction::None);
|
||||||
|
} else {
|
||||||
|
let lpad = lpad_base + cs_lpad;
|
||||||
|
return Ok(interpret_cs_action(cs_action, lpad, foreign_exception));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Ip is not present in the table. This should not happen... but it does: issue #35011.
|
||||||
|
// So rather than returning EHAction::Terminate, we do this.
|
||||||
|
Ok(EHAction::None)
|
||||||
|
} else {
|
||||||
|
// SjLj version:
|
||||||
|
// The "IP" is an index into the call-site table, with two exceptions:
|
||||||
|
// -1 means 'no-action', and 0 means 'terminate'.
|
||||||
|
match ip as isize {
|
||||||
|
-1 => return Ok(EHAction::None),
|
||||||
|
0 => return Ok(EHAction::Terminate),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
let mut idx = ip;
|
||||||
|
loop {
|
||||||
|
let cs_lpad = reader.read_uleb128();
|
||||||
|
let cs_action = reader.read_uleb128();
|
||||||
|
idx -= 1;
|
||||||
|
if idx == 0 {
|
||||||
|
// Can never have null landing pad for sjlj -- that would have
|
||||||
|
// been indicated by a -1 call site index.
|
||||||
|
let lpad = (cs_lpad + 1) as usize;
|
||||||
|
return Ok(interpret_cs_action(cs_action, lpad, foreign_exception));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn interpret_cs_action(cs_action: u64, lpad: usize, foreign_exception: bool) -> EHAction {
|
||||||
|
if cs_action == 0 {
|
||||||
|
// If cs_action is 0 then this is a cleanup (Drop::drop). We run these
|
||||||
|
// for both Rust panics and foreign exceptions.
|
||||||
|
EHAction::Cleanup(lpad)
|
||||||
|
} else if foreign_exception {
|
||||||
|
// catch_unwind should not catch foreign exceptions, only Rust panics.
|
||||||
|
// Instead just continue unwinding.
|
||||||
|
EHAction::None
|
||||||
|
} else {
|
||||||
|
// Stop unwinding Rust panics at catch_unwind.
|
||||||
|
EHAction::Catch(lpad)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn round_up(unrounded: usize, align: usize) -> Result<usize, ()> {
|
||||||
|
if align.is_power_of_two() { Ok((unrounded + align - 1) & !(align - 1)) } else { Err(()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn read_encoded_pointer(
|
||||||
|
reader: &mut DwarfReader,
|
||||||
|
context: &EHContext<'_>,
|
||||||
|
encoding: u8,
|
||||||
|
) -> Result<usize, ()> {
|
||||||
|
if encoding == DW_EH_PE_omit {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// DW_EH_PE_aligned implies it's an absolute pointer value
|
||||||
|
if encoding == DW_EH_PE_aligned {
|
||||||
|
reader.ptr = round_up(reader.ptr as usize, mem::size_of::<usize>())? as *const u8;
|
||||||
|
return Ok(reader.read::<usize>());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut result = match encoding & 0x0F {
|
||||||
|
DW_EH_PE_absptr => reader.read::<usize>(),
|
||||||
|
DW_EH_PE_uleb128 => reader.read_uleb128() as usize,
|
||||||
|
DW_EH_PE_udata2 => reader.read::<u16>() as usize,
|
||||||
|
DW_EH_PE_udata4 => reader.read::<u32>() as usize,
|
||||||
|
DW_EH_PE_udata8 => reader.read::<u64>() as usize,
|
||||||
|
DW_EH_PE_sleb128 => reader.read_sleb128() as usize,
|
||||||
|
DW_EH_PE_sdata2 => reader.read::<i16>() as usize,
|
||||||
|
DW_EH_PE_sdata4 => reader.read::<i32>() as usize,
|
||||||
|
DW_EH_PE_sdata8 => reader.read::<i64>() as usize,
|
||||||
|
_ => return Err(()),
|
||||||
|
};
|
||||||
|
|
||||||
|
result += match encoding & 0x70 {
|
||||||
|
DW_EH_PE_absptr => 0,
|
||||||
|
// relative to address of the encoded value, despite the name
|
||||||
|
DW_EH_PE_pcrel => reader.ptr as usize,
|
||||||
|
DW_EH_PE_funcrel => {
|
||||||
|
if context.func_start == 0 {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
context.func_start
|
||||||
|
}
|
||||||
|
DW_EH_PE_textrel => (*context.get_text_start)(),
|
||||||
|
DW_EH_PE_datarel => (*context.get_data_start)(),
|
||||||
|
_ => return Err(()),
|
||||||
|
};
|
||||||
|
|
||||||
|
if encoding & DW_EH_PE_indirect != 0 {
|
||||||
|
result = *(result as *const usize);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
//! Utilities for parsing DWARF-encoded data streams.
|
||||||
|
//! See <http://www.dwarfstd.org>,
|
||||||
|
//! DWARF-4 standard, Section 7 - "Data Representation"
|
||||||
|
|
||||||
|
#![no_std]
|
||||||
|
// This module is used only by x86_64-pc-windows-gnu for now, but we
|
||||||
|
// are compiling it everywhere to avoid regressions.
|
||||||
|
#![allow(unused)]
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
||||||
|
|
||||||
|
pub mod eh;
|
||||||
|
|
||||||
|
use core::mem;
|
||||||
|
|
||||||
|
pub struct DwarfReader {
|
||||||
|
pub ptr: *const u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C, packed)]
|
||||||
|
struct Unaligned<T>(T);
|
||||||
|
|
||||||
|
impl DwarfReader {
|
||||||
|
pub fn new(ptr: *const u8) -> DwarfReader {
|
||||||
|
DwarfReader { 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.
|
||||||
|
pub unsafe fn read<T: Copy>(&mut self) -> T {
|
||||||
|
let Unaligned(result) = *(self.ptr as *const Unaligned<T>);
|
||||||
|
self.ptr = self.ptr.add(mem::size_of::<T>());
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
// ULEB128 and SLEB128 encodings are defined in Section 7.6 - "Variable
|
||||||
|
// Length Data".
|
||||||
|
pub 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
|
||||||
|
}
|
||||||
|
|
||||||
|
pub 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
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dwarf_reader() {
|
||||||
|
let encoded: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 0xE5, 0x8E, 0x26, 0x9B, 0xF1, 0x59, 0xFF, 0xFF];
|
||||||
|
|
||||||
|
let mut reader = DwarfReader::new(encoded.as_ptr());
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
assert!(reader.read::<u8>() == u8::to_be(1u8));
|
||||||
|
assert!(reader.read::<u16>() == u16::to_be(0x0203));
|
||||||
|
assert!(reader.read::<u32>() == u32::to_be(0x04050607));
|
||||||
|
|
||||||
|
assert!(reader.read_uleb128() == 624485);
|
||||||
|
assert!(reader.read_sleb128() == -624485);
|
||||||
|
|
||||||
|
assert!(reader.read::<i8>() == i8::to_be(-1));
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
use core::{ops::Range, convert, fmt, str};
|
use core::{convert, fmt, str};
|
||||||
use alloc::string::String;
|
use alloc::string::String;
|
||||||
use log::{debug, trace};
|
use log::{debug, trace};
|
||||||
use elf::*;
|
use elf::*;
|
||||||
|
@ -57,10 +57,43 @@ fn elf_hash(name: &[u8]) -> u32 {
|
||||||
h
|
h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// linker symbols
|
||||||
|
extern "C" {
|
||||||
|
#[no_mangle]
|
||||||
|
static __text_start: u32;
|
||||||
|
#[no_mangle]
|
||||||
|
static __text_end: u32;
|
||||||
|
#[no_mangle]
|
||||||
|
static __exidx_start: u32;
|
||||||
|
#[no_mangle]
|
||||||
|
static __exidx_end: u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
static mut KERNEL_EXIDX_START: u32 = 0;
|
||||||
|
static mut KERNEL_EXIDX_END: u32 = 0;
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern fn dl_unwind_find_exidx(pc: u32, len_ptr: *mut u32) -> u32 {
|
||||||
|
let length: u32;
|
||||||
|
let start: u32;
|
||||||
|
unsafe {
|
||||||
|
if (&__text_start as *const u32 as u32) <= pc && pc < (&__text_end as *const u32 as u32) {
|
||||||
|
length = (&__exidx_end - &__exidx_start) as u32;
|
||||||
|
start = &__exidx_start as *const u32 as u32;
|
||||||
|
} else {
|
||||||
|
// make sure that the kernel is loaded
|
||||||
|
assert_ne!(KERNEL_EXIDX_START, 0);
|
||||||
|
length = (KERNEL_EXIDX_END - KERNEL_EXIDX_START) / core::mem::size_of::<u32>() as u32;
|
||||||
|
start = KERNEL_EXIDX_START;
|
||||||
|
}
|
||||||
|
*len_ptr = length;
|
||||||
|
}
|
||||||
|
start
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Library {
|
pub struct Library {
|
||||||
pub image: Image,
|
pub image: Image,
|
||||||
dyn_section: DynamicSection,
|
dyn_section: DynamicSection,
|
||||||
exidx: Range<usize>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Library {
|
impl Library {
|
||||||
|
@ -130,10 +163,6 @@ impl Library {
|
||||||
Ok(self.strtab().get(offset..offset + size)
|
Ok(self.strtab().get(offset..offset + size)
|
||||||
.ok_or("cannot read symbol name")?)
|
.ok_or("cannot read symbol name")?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exidx(&self) -> &[usize] {
|
|
||||||
self.image.get_ref_slice_unchecked(&self.exidx)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load(
|
pub fn load(
|
||||||
|
@ -169,7 +198,6 @@ pub fn load(
|
||||||
.map_err(|_| "cannot allocate target image")?;
|
.map_err(|_| "cannot allocate target image")?;
|
||||||
debug!("ELF target: {} bytes, align to {:X}, allocated at {:08X}", image_size, image_align, image.ptr() as usize);
|
debug!("ELF target: {} bytes, align to {:X}, allocated at {:08X}", image_size, image_align, image.ptr() as usize);
|
||||||
|
|
||||||
let mut exidx = None;
|
|
||||||
// LOAD
|
// LOAD
|
||||||
for phdr in file.program_headers() {
|
for phdr in file.program_headers() {
|
||||||
let phdr = phdr.ok_or("cannot read program header")?;
|
let phdr = phdr.ok_or("cannot read program header")?;
|
||||||
|
@ -188,8 +216,13 @@ pub fn load(
|
||||||
dst.copy_from_slice(src);
|
dst.copy_from_slice(src);
|
||||||
}
|
}
|
||||||
PT_ARM_EXIDX => {
|
PT_ARM_EXIDX => {
|
||||||
exidx = Some(phdr.p_vaddr as usize..
|
let range = image.get(phdr.p_vaddr as usize..
|
||||||
(phdr.p_vaddr + phdr.p_filesz) as usize);
|
(phdr.p_vaddr + phdr.p_filesz) as usize)
|
||||||
|
.ok_or("program header requests and out of bounds load (in target)")?;
|
||||||
|
unsafe {
|
||||||
|
KERNEL_EXIDX_START = range.as_ptr() as u32;
|
||||||
|
KERNEL_EXIDX_END = range.as_ptr().add(range.len()) as u32;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
@ -203,8 +236,7 @@ pub fn load(
|
||||||
dyn_section.rela.len(), dyn_section.rel.len(), dyn_section.pltrel.len());
|
dyn_section.rela.len(), dyn_section.rel.len(), dyn_section.pltrel.len());
|
||||||
let lib = Library {
|
let lib = Library {
|
||||||
image,
|
image,
|
||||||
dyn_section,
|
dyn_section
|
||||||
exidx: exidx.ok_or("missing EXIDX program header")?,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for rela in lib.rela() {
|
for rela in lib.rela() {
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
[package]
|
||||||
|
authors = ["The Rust Project Developers"]
|
||||||
|
name = "unwind"
|
||||||
|
version = "0.0.0"
|
||||||
|
build = "build.rs"
|
||||||
|
edition = "2018"
|
||||||
|
include = [
|
||||||
|
'/libunwind/*',
|
||||||
|
]
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "unwind"
|
||||||
|
path = "lib.rs"
|
||||||
|
test = false
|
||||||
|
bench = false
|
||||||
|
doc = false
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
compiler_builtins = "0.1.0"
|
||||||
|
cfg-if = "0.1.8"
|
||||||
|
libc = { path = "../libc" }
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
cc = { version = "1.0.1" }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
llvm-libunwind = []
|
|
@ -0,0 +1,41 @@
|
||||||
|
use libc::{c_void, c_int};
|
||||||
|
use crate::libunwind as uw;
|
||||||
|
|
||||||
|
const UW_REG_SP: c_int = 13;
|
||||||
|
|
||||||
|
pub fn backtrace<F>(f: F) -> Result<(), uw::_Unwind_Reason_Code>
|
||||||
|
where F: FnMut(usize) -> ()
|
||||||
|
{
|
||||||
|
struct TraceContext<F> {
|
||||||
|
step_fn: F,
|
||||||
|
prev_sp: uw::_Unwind_Word
|
||||||
|
}
|
||||||
|
|
||||||
|
extern fn trace<F>(context: *mut uw::_Unwind_Context, arg: *mut c_void)
|
||||||
|
-> uw::_Unwind_Reason_Code
|
||||||
|
where F: FnMut(usize) -> ()
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
let trace_context = &mut *(arg as *mut TraceContext<F>);
|
||||||
|
|
||||||
|
// Detect the root of a libfringe thread
|
||||||
|
let cur_sp = uw::_Unwind_GetGR(context, UW_REG_SP);
|
||||||
|
if cur_sp == trace_context.prev_sp {
|
||||||
|
return uw::_URC_END_OF_STACK
|
||||||
|
} else {
|
||||||
|
trace_context.prev_sp = cur_sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
(trace_context.step_fn)(uw::_Unwind_GetIP(context));
|
||||||
|
uw::_URC_NO_REASON
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let mut trace_context = TraceContext { step_fn: f, prev_sp: 0 };
|
||||||
|
match uw::_Unwind_Backtrace(trace::<F>, &mut trace_context as *mut _ as *mut c_void) {
|
||||||
|
uw::_URC_NO_REASON => Ok(()),
|
||||||
|
err => Err(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
fn main() {
|
||||||
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
llvm_libunwind::compile();
|
||||||
|
}
|
||||||
|
|
||||||
|
mod llvm_libunwind {
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
/// Compile the libunwind C/C++ source code.
|
||||||
|
pub fn compile() {
|
||||||
|
let cfg = &mut cc::Build::new();
|
||||||
|
cfg.cpp(true);
|
||||||
|
cfg.cpp_set_stdlib(None);
|
||||||
|
cfg.warnings(false);
|
||||||
|
|
||||||
|
// libunwind expects a __LITTLE_ENDIAN__ macro to be set for LE archs, cf. #65765
|
||||||
|
cfg.define("__LITTLE_ENDIAN__", Some("1"));
|
||||||
|
// still have problem compiling the libunwind
|
||||||
|
cfg.flag("-nostdlib");
|
||||||
|
cfg.flag("-ffreestanding");
|
||||||
|
cfg.flag("-fno-PIC");
|
||||||
|
cfg.flag("-Isrc");
|
||||||
|
cfg.flag("-I../include");
|
||||||
|
cfg.flag("-fno-stack-protector");
|
||||||
|
cfg.flag("--target=armv7-none-eabihf");
|
||||||
|
cfg.define("_LIBUNWIND_IS_BAREMETAL", Some("1"));
|
||||||
|
cfg.define("_LIBUNWIND_NO_HEAP", Some("1"));
|
||||||
|
cfg.define("_POSIX_READER_WRITER_LOCKS", Some("1"));
|
||||||
|
cfg.define("NDEBUG", Some("1"));
|
||||||
|
|
||||||
|
cfg.flag("-std=c99");
|
||||||
|
cfg.flag("-std=c++11");
|
||||||
|
cfg.flag("-nostdinc++");
|
||||||
|
cfg.flag("-fno-exceptions");
|
||||||
|
cfg.flag("-fno-rtti");
|
||||||
|
cfg.flag("-fstrict-aliasing");
|
||||||
|
cfg.flag("-funwind-tables");
|
||||||
|
cfg.flag("-fvisibility=hidden");
|
||||||
|
cfg.flag_if_supported("-fvisibility-global-new-delete-hidden");
|
||||||
|
cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
|
||||||
|
|
||||||
|
let unwind_sources = vec![
|
||||||
|
"Unwind-EHABI.cpp",
|
||||||
|
"Unwind-seh.cpp",
|
||||||
|
"Unwind-sjlj.c",
|
||||||
|
"UnwindLevel1-gcc-ext.c",
|
||||||
|
"UnwindLevel1.c",
|
||||||
|
"UnwindRegistersRestore.S",
|
||||||
|
"UnwindRegistersSave.S",
|
||||||
|
"libunwind.cpp",
|
||||||
|
"printf.c",
|
||||||
|
];
|
||||||
|
|
||||||
|
let root = Path::new("../llvm_libunwind");
|
||||||
|
cfg.include(root.join("include"));
|
||||||
|
for src in unwind_sources {
|
||||||
|
cfg.file(root.join("src").join(src));
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.compile("unwind");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
#![no_std]
|
||||||
|
#![feature(link_cfg)]
|
||||||
|
#![feature(nll)]
|
||||||
|
#![feature(unwind_attributes)]
|
||||||
|
#![feature(static_nobundle)]
|
||||||
|
#![cfg_attr(not(target_env = "msvc"), feature(libc))]
|
||||||
|
|
||||||
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(target_env = "msvc")] {
|
||||||
|
// no extra unwinder support needed
|
||||||
|
} else if #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] {
|
||||||
|
// no unwinder on the system!
|
||||||
|
} else {
|
||||||
|
mod libunwind;
|
||||||
|
pub use libunwind::*;
|
||||||
|
mod backtrace;
|
||||||
|
pub use backtrace::backtrace;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_env = "musl")]
|
||||||
|
#[link(name = "unwind", kind = "static", cfg(target_feature = "crt-static"))]
|
||||||
|
#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
|
||||||
|
extern "C" {}
|
||||||
|
|
||||||
|
#[cfg(target_os = "redox")]
|
||||||
|
#[link(name = "gcc_eh", kind = "static-nobundle", cfg(target_feature = "crt-static"))]
|
||||||
|
#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
|
||||||
|
extern "C" {}
|
||||||
|
|
||||||
|
#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
|
||||||
|
#[link(name = "unwind", kind = "static-nobundle")]
|
||||||
|
extern "C" {}
|
|
@ -0,0 +1,285 @@
|
||||||
|
#![allow(nonstandard_style)]
|
||||||
|
|
||||||
|
use libc::{c_int, c_void, uintptr_t};
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
|
pub enum _Unwind_Reason_Code {
|
||||||
|
_URC_NO_REASON = 0,
|
||||||
|
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
|
||||||
|
_URC_FATAL_PHASE2_ERROR = 2,
|
||||||
|
_URC_FATAL_PHASE1_ERROR = 3,
|
||||||
|
_URC_NORMAL_STOP = 4,
|
||||||
|
_URC_END_OF_STACK = 5,
|
||||||
|
_URC_HANDLER_FOUND = 6,
|
||||||
|
_URC_INSTALL_CONTEXT = 7,
|
||||||
|
_URC_CONTINUE_UNWIND = 8,
|
||||||
|
_URC_FAILURE = 9, // used only by ARM EHABI
|
||||||
|
}
|
||||||
|
pub use _Unwind_Reason_Code::*;
|
||||||
|
|
||||||
|
pub type _Unwind_Exception_Class = u64;
|
||||||
|
pub type _Unwind_Word = uintptr_t;
|
||||||
|
pub type _Unwind_Ptr = uintptr_t;
|
||||||
|
pub type _Unwind_Trace_Fn =
|
||||||
|
extern "C" fn(ctx: *mut _Unwind_Context, arg: *mut c_void) -> _Unwind_Reason_Code;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86")]
|
||||||
|
pub const unwinder_private_data_size: usize = 5;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
pub const unwinder_private_data_size: usize = 6;
|
||||||
|
|
||||||
|
#[cfg(all(target_arch = "arm", not(target_os = "ios")))]
|
||||||
|
pub const unwinder_private_data_size: usize = 20;
|
||||||
|
|
||||||
|
#[cfg(all(target_arch = "arm", target_os = "ios"))]
|
||||||
|
pub const unwinder_private_data_size: usize = 5;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
pub const unwinder_private_data_size: usize = 2;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "mips")]
|
||||||
|
pub const unwinder_private_data_size: usize = 2;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "mips64")]
|
||||||
|
pub const unwinder_private_data_size: usize = 2;
|
||||||
|
|
||||||
|
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
|
||||||
|
pub const unwinder_private_data_size: usize = 2;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "s390x")]
|
||||||
|
pub const unwinder_private_data_size: usize = 2;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "sparc64")]
|
||||||
|
pub const unwinder_private_data_size: usize = 2;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
pub const unwinder_private_data_size: usize = 2;
|
||||||
|
|
||||||
|
#[cfg(target_os = "emscripten")]
|
||||||
|
pub const unwinder_private_data_size: usize = 20;
|
||||||
|
|
||||||
|
#[cfg(all(target_arch = "hexagon", target_os = "linux"))]
|
||||||
|
pub const unwinder_private_data_size: usize = 35;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct _Unwind_Exception {
|
||||||
|
pub exception_class: _Unwind_Exception_Class,
|
||||||
|
pub exception_cleanup: _Unwind_Exception_Cleanup_Fn,
|
||||||
|
pub private: [_Unwind_Word; unwinder_private_data_size],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum _Unwind_Context {}
|
||||||
|
|
||||||
|
pub type _Unwind_Exception_Cleanup_Fn =
|
||||||
|
extern "C" fn(unwind_code: _Unwind_Reason_Code, exception: *mut _Unwind_Exception);
|
||||||
|
#[cfg_attr(
|
||||||
|
all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")),
|
||||||
|
link(name = "unwind", kind = "static")
|
||||||
|
)]
|
||||||
|
extern "C" {
|
||||||
|
#[unwind(allowed)]
|
||||||
|
pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !;
|
||||||
|
pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception);
|
||||||
|
pub fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> *mut c_void;
|
||||||
|
pub fn _Unwind_GetRegionStart(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
|
||||||
|
pub fn _Unwind_GetTextRelBase(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
|
||||||
|
pub fn _Unwind_GetDataRelBase(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(all(any(target_os = "ios", target_os = "netbsd", not(target_arch = "arm"))))] {
|
||||||
|
// Not ARM EHABI
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
|
pub enum _Unwind_Action {
|
||||||
|
_UA_SEARCH_PHASE = 1,
|
||||||
|
_UA_CLEANUP_PHASE = 2,
|
||||||
|
_UA_HANDLER_FRAME = 4,
|
||||||
|
_UA_FORCE_UNWIND = 8,
|
||||||
|
_UA_END_OF_STACK = 16,
|
||||||
|
}
|
||||||
|
pub use _Unwind_Action::*;
|
||||||
|
|
||||||
|
#[cfg_attr(all(feature = "llvm-libunwind",
|
||||||
|
any(target_os = "fuchsia", target_os = "linux")),
|
||||||
|
link(name = "unwind", kind = "static"))]
|
||||||
|
extern "C" {
|
||||||
|
pub fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word;
|
||||||
|
pub fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word);
|
||||||
|
pub fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> _Unwind_Word;
|
||||||
|
pub fn _Unwind_SetIP(ctx: *mut _Unwind_Context, value: _Unwind_Word);
|
||||||
|
pub fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context, ip_before_insn: *mut c_int)
|
||||||
|
-> _Unwind_Word;
|
||||||
|
pub fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// ARM EHABI
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
|
pub enum _Unwind_State {
|
||||||
|
_US_VIRTUAL_UNWIND_FRAME = 0,
|
||||||
|
_US_UNWIND_FRAME_STARTING = 1,
|
||||||
|
_US_UNWIND_FRAME_RESUME = 2,
|
||||||
|
_US_ACTION_MASK = 3,
|
||||||
|
_US_FORCE_UNWIND = 8,
|
||||||
|
_US_END_OF_STACK = 16,
|
||||||
|
}
|
||||||
|
pub use _Unwind_State::*;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
enum _Unwind_VRS_Result {
|
||||||
|
_UVRSR_OK = 0,
|
||||||
|
_UVRSR_NOT_IMPLEMENTED = 1,
|
||||||
|
_UVRSR_FAILED = 2,
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
enum _Unwind_VRS_RegClass {
|
||||||
|
_UVRSC_CORE = 0,
|
||||||
|
_UVRSC_VFP = 1,
|
||||||
|
_UVRSC_FPA = 2,
|
||||||
|
_UVRSC_WMMXD = 3,
|
||||||
|
_UVRSC_WMMXC = 4,
|
||||||
|
}
|
||||||
|
use _Unwind_VRS_RegClass::*;
|
||||||
|
#[repr(C)]
|
||||||
|
enum _Unwind_VRS_DataRepresentation {
|
||||||
|
_UVRSD_UINT32 = 0,
|
||||||
|
_UVRSD_VFPX = 1,
|
||||||
|
_UVRSD_FPAX = 2,
|
||||||
|
_UVRSD_UINT64 = 3,
|
||||||
|
_UVRSD_FLOAT = 4,
|
||||||
|
_UVRSD_DOUBLE = 5,
|
||||||
|
}
|
||||||
|
use _Unwind_VRS_DataRepresentation::*;
|
||||||
|
|
||||||
|
pub const UNWIND_POINTER_REG: c_int = 12;
|
||||||
|
pub const UNWIND_SP_REG: c_int = 13;
|
||||||
|
pub const UNWIND_IP_REG: c_int = 15;
|
||||||
|
|
||||||
|
#[cfg_attr(all(feature = "llvm-libunwind",
|
||||||
|
any(target_os = "fuchsia", target_os = "linux")),
|
||||||
|
link(name = "unwind", kind = "static"))]
|
||||||
|
extern "C" {
|
||||||
|
fn _Unwind_VRS_Get(ctx: *mut _Unwind_Context,
|
||||||
|
regclass: _Unwind_VRS_RegClass,
|
||||||
|
regno: _Unwind_Word,
|
||||||
|
repr: _Unwind_VRS_DataRepresentation,
|
||||||
|
data: *mut c_void)
|
||||||
|
-> _Unwind_VRS_Result;
|
||||||
|
|
||||||
|
fn _Unwind_VRS_Set(ctx: *mut _Unwind_Context,
|
||||||
|
regclass: _Unwind_VRS_RegClass,
|
||||||
|
regno: _Unwind_Word,
|
||||||
|
repr: _Unwind_VRS_DataRepresentation,
|
||||||
|
data: *mut c_void)
|
||||||
|
-> _Unwind_VRS_Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// On Android or ARM/Linux, these are implemented as macros:
|
||||||
|
|
||||||
|
pub unsafe fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word {
|
||||||
|
let mut val: _Unwind_Word = 0;
|
||||||
|
_Unwind_VRS_Get(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32,
|
||||||
|
&mut val as *mut _ as *mut c_void);
|
||||||
|
val
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word) {
|
||||||
|
let mut value = value;
|
||||||
|
_Unwind_VRS_Set(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32,
|
||||||
|
&mut value as *mut _ as *mut c_void);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context)
|
||||||
|
-> _Unwind_Word {
|
||||||
|
let val = _Unwind_GetGR(ctx, UNWIND_IP_REG);
|
||||||
|
(val & !1) as _Unwind_Word
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn _Unwind_SetIP(ctx: *mut _Unwind_Context,
|
||||||
|
value: _Unwind_Word) {
|
||||||
|
// Propagate thumb bit to instruction pointer
|
||||||
|
let thumb_state = _Unwind_GetGR(ctx, UNWIND_IP_REG) & 1;
|
||||||
|
let value = value | thumb_state;
|
||||||
|
_Unwind_SetGR(ctx, UNWIND_IP_REG, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context,
|
||||||
|
ip_before_insn: *mut c_int)
|
||||||
|
-> _Unwind_Word {
|
||||||
|
*ip_before_insn = 0;
|
||||||
|
_Unwind_GetIP(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function also doesn't exist on Android or ARM/Linux, so make it a no-op
|
||||||
|
pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void {
|
||||||
|
pc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // cfg_if!
|
||||||
|
|
||||||
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] {
|
||||||
|
// Not 32-bit iOS
|
||||||
|
#[cfg_attr(all(feature = "llvm-libunwind",
|
||||||
|
any(target_os = "fuchsia", target_os = "linux")),
|
||||||
|
link(name = "unwind", kind = "static"))]
|
||||||
|
extern "C" {
|
||||||
|
#[unwind(allowed)]
|
||||||
|
pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
|
||||||
|
pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
|
||||||
|
trace_argument: *mut c_void)
|
||||||
|
-> _Unwind_Reason_Code;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 32-bit iOS uses SjLj and does not provide _Unwind_Backtrace()
|
||||||
|
#[cfg_attr(all(feature = "llvm-libunwind",
|
||||||
|
any(target_os = "fuchsia", target_os = "linux")),
|
||||||
|
link(name = "unwind", kind = "static"))]
|
||||||
|
extern "C" {
|
||||||
|
#[unwind(allowed)]
|
||||||
|
pub fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn _Unwind_RaiseException(exc: *mut _Unwind_Exception) -> _Unwind_Reason_Code {
|
||||||
|
_Unwind_SjLj_RaiseException(exc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // cfg_if!
|
||||||
|
|
||||||
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(all(windows, target_arch = "x86_64", target_env = "gnu"))] {
|
||||||
|
// We declare these as opaque types. This is fine since you just need to
|
||||||
|
// pass them to _GCC_specific_handler and forget about them.
|
||||||
|
pub enum EXCEPTION_RECORD {}
|
||||||
|
pub type LPVOID = *mut c_void;
|
||||||
|
pub enum CONTEXT {}
|
||||||
|
pub enum DISPATCHER_CONTEXT {}
|
||||||
|
pub type EXCEPTION_DISPOSITION = c_int;
|
||||||
|
type PersonalityFn = unsafe extern "C" fn(version: c_int,
|
||||||
|
actions: _Unwind_Action,
|
||||||
|
exception_class: _Unwind_Exception_Class,
|
||||||
|
exception_object: *mut _Unwind_Exception,
|
||||||
|
context: *mut _Unwind_Context)
|
||||||
|
-> _Unwind_Reason_Code;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
pub fn _GCC_specific_handler(exceptionRecord: *mut EXCEPTION_RECORD,
|
||||||
|
establisherFrame: LPVOID,
|
||||||
|
contextRecord: *mut CONTEXT,
|
||||||
|
dispatcherContext: *mut DISPATCHER_CONTEXT,
|
||||||
|
personality: PersonalityFn)
|
||||||
|
-> EXCEPTION_DISPOSITION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // cfg_if!
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern fn abort() {
|
||||||
|
panic!("Abort!");
|
||||||
|
}
|
||||||
|
|
|
@ -20,8 +20,11 @@ void = { version = "1", default-features = false }
|
||||||
futures = { version = "0.3", default-features = false, features = ["async-await"] }
|
futures = { version = "0.3", default-features = false, features = ["async-await"] }
|
||||||
async-recursion = "0.3"
|
async-recursion = "0.3"
|
||||||
libboard_zynq = { git = "https://git.m-labs.hk/M-Labs/zc706.git" }
|
libboard_zynq = { git = "https://git.m-labs.hk/M-Labs/zc706.git" }
|
||||||
libsupport_zynq = { git = "https://git.m-labs.hk/M-Labs/zc706.git" }
|
libsupport_zynq = { default-features = false, git = "https://git.m-labs.hk/M-Labs/zc706.git" }
|
||||||
libcortex_a9 = { git = "https://git.m-labs.hk/M-Labs/zc706.git" }
|
libcortex_a9 = { git = "https://git.m-labs.hk/M-Labs/zc706.git" }
|
||||||
libasync = { git = "https://git.m-labs.hk/M-Labs/zc706.git" }
|
libasync = { git = "https://git.m-labs.hk/M-Labs/zc706.git" }
|
||||||
dyld = { path = "../libdyld" }
|
dyld = { path = "../libdyld" }
|
||||||
|
dwarf = { path = "../libdwarf" }
|
||||||
|
unwind = { path = "../libunwind" }
|
||||||
|
libc = { path = "../libc" }
|
||||||
fatfs = { version = "0.3", features = ["core_io"], default-features = false }
|
fatfs = { version = "0.3", features = ["core_io"], default-features = false }
|
||||||
|
|
|
@ -17,12 +17,26 @@ MEMORY
|
||||||
|
|
||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
|
__text_start = .;
|
||||||
.text :
|
.text :
|
||||||
{
|
{
|
||||||
KEEP(*(.text.exceptions));
|
KEEP(*(.text.exceptions));
|
||||||
*(.text.boot);
|
*(.text.boot);
|
||||||
*(.text .text.*);
|
*(.text .text.*);
|
||||||
} > SDRAM
|
} > SDRAM
|
||||||
|
__text_end = .;
|
||||||
|
|
||||||
|
__exidx_start = .;
|
||||||
|
.ARM.exidx :
|
||||||
|
{
|
||||||
|
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||||
|
} > SDRAM
|
||||||
|
__exidx_end = .;
|
||||||
|
|
||||||
|
.ARM.extab :
|
||||||
|
{
|
||||||
|
* (.ARM.extab*)
|
||||||
|
} > SDRAM
|
||||||
|
|
||||||
.rodata : ALIGN(4)
|
.rodata : ALIGN(4)
|
||||||
{
|
{
|
||||||
|
@ -62,12 +76,4 @@ SECTIONS
|
||||||
. += 0x10000;
|
. += 0x10000;
|
||||||
__stack0_start = .;
|
__stack0_start = .;
|
||||||
} > SDRAM
|
} > SDRAM
|
||||||
|
|
||||||
/DISCARD/ :
|
|
||||||
{
|
|
||||||
/* Unused exception related info that only wastes space */
|
|
||||||
*(.ARM.exidx);
|
|
||||||
*(.ARM.exidx.*);
|
|
||||||
*(.ARM.extab.*);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,209 @@
|
||||||
|
// Portions of the code in this file are derived from code by RUST developers.
|
||||||
|
// Modified to suit the case of artiq-zynq port, for ARM EHABI.
|
||||||
|
#![allow(non_camel_case_types)]
|
||||||
|
|
||||||
|
use core::mem;
|
||||||
|
use cslice::CSlice;
|
||||||
|
use unwind as uw;
|
||||||
|
use libc::{c_int, uintptr_t};
|
||||||
|
use log::debug;
|
||||||
|
|
||||||
|
use dwarf::eh::{self, EHAction, EHContext};
|
||||||
|
|
||||||
|
|
||||||
|
const EXCEPTION_CLASS: uw::_Unwind_Exception_Class = 0x4d_4c_42_53_41_52_54_51; /* 'MLBSARTQ' */
|
||||||
|
|
||||||
|
#[cfg(target_arch = "arm")]
|
||||||
|
const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1
|
||||||
|
|
||||||
|
#[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 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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsafe fn find_eh_action(
|
||||||
|
context: *mut uw::_Unwind_Context,
|
||||||
|
foreign_exception: bool,
|
||||||
|
) -> Result<EHAction, ()> {
|
||||||
|
let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8;
|
||||||
|
let mut ip_before_instr: c_int = 0;
|
||||||
|
let ip = uw::_Unwind_GetIPInfo(context, &mut ip_before_instr);
|
||||||
|
let eh_context = EHContext {
|
||||||
|
// The return address points 1 byte past the call instruction,
|
||||||
|
// which could be in the next IP range in LSDA range table.
|
||||||
|
ip: if ip_before_instr != 0 { ip } else { ip - 1 },
|
||||||
|
func_start: uw::_Unwind_GetRegionStart(context),
|
||||||
|
get_text_start: &|| uw::_Unwind_GetTextRelBase(context),
|
||||||
|
get_data_start: &|| uw::_Unwind_GetDataRelBase(context),
|
||||||
|
};
|
||||||
|
eh::find_eh_action(lsda, &eh_context, foreign_exception)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn artiq_personality(state: uw::_Unwind_State,
|
||||||
|
exception_object: *mut uw::_Unwind_Exception,
|
||||||
|
context: *mut uw::_Unwind_Context)
|
||||||
|
-> uw::_Unwind_Reason_Code {
|
||||||
|
let state = state as c_int;
|
||||||
|
let action = state & uw::_US_ACTION_MASK as c_int;
|
||||||
|
let search_phase = if action == uw::_US_VIRTUAL_UNWIND_FRAME as c_int {
|
||||||
|
// Backtraces on ARM will call the personality routine with
|
||||||
|
// state == _US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND. In those cases
|
||||||
|
// we want to continue unwinding the stack, otherwise all our backtraces
|
||||||
|
// would end at __rust_try
|
||||||
|
if state & uw::_US_FORCE_UNWIND as c_int != 0 {
|
||||||
|
return continue_unwind(exception_object, context);
|
||||||
|
}
|
||||||
|
true
|
||||||
|
} else if action == uw::_US_UNWIND_FRAME_STARTING as c_int {
|
||||||
|
false
|
||||||
|
} else if action == uw::_US_UNWIND_FRAME_RESUME as c_int {
|
||||||
|
return continue_unwind(exception_object, context);
|
||||||
|
} else {
|
||||||
|
return uw::_URC_FAILURE;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The DWARF unwinder assumes that _Unwind_Context holds things like the function
|
||||||
|
// and LSDA pointers, however ARM EHABI places them into the exception object.
|
||||||
|
// To preserve signatures of functions like _Unwind_GetLanguageSpecificData(), which
|
||||||
|
// take only the context pointer, GCC personality routines stash a pointer to
|
||||||
|
// exception_object in the context, using location reserved for ARM's
|
||||||
|
// "scratch register" (r12).
|
||||||
|
uw::_Unwind_SetGR(context,
|
||||||
|
uw::UNWIND_POINTER_REG,
|
||||||
|
exception_object as uw::_Unwind_Ptr);
|
||||||
|
// ...A more principled approach would be to provide the full definition of ARM's
|
||||||
|
// _Unwind_Context in our libunwind bindings and fetch the required data from there
|
||||||
|
// directly, bypassing DWARF compatibility functions.
|
||||||
|
|
||||||
|
let exception_class = (*exception_object).exception_class;
|
||||||
|
let foreign_exception = exception_class != EXCEPTION_CLASS;
|
||||||
|
let eh_action = match find_eh_action(context, foreign_exception) {
|
||||||
|
Ok(action) => action,
|
||||||
|
Err(_) => return uw::_URC_FAILURE,
|
||||||
|
};
|
||||||
|
let exception_info = &mut *(exception_object as *mut ExceptionInfo);
|
||||||
|
let exception = &exception_info.exception.unwrap();
|
||||||
|
if search_phase {
|
||||||
|
match eh_action {
|
||||||
|
EHAction::None |
|
||||||
|
EHAction::Cleanup(_) => return continue_unwind(exception_object, context),
|
||||||
|
EHAction::Catch(_) => {
|
||||||
|
// EHABI requires the personality routine to update the
|
||||||
|
// SP value in the barrier cache of the exception object.
|
||||||
|
(*exception_object).private[5] =
|
||||||
|
uw::_Unwind_GetGR(context, uw::UNWIND_SP_REG);
|
||||||
|
return uw::_URC_HANDLER_FOUND;
|
||||||
|
}
|
||||||
|
EHAction::Terminate => return uw::_URC_FAILURE,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match eh_action {
|
||||||
|
EHAction::None => return continue_unwind(exception_object, context),
|
||||||
|
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, exception as *const _ as uw::_Unwind_Word);
|
||||||
|
uw::_Unwind_SetIP(context, lpad);
|
||||||
|
return uw::_URC_INSTALL_CONTEXT;
|
||||||
|
}
|
||||||
|
EHAction::Terminate => return uw::_URC_FAILURE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// On ARM EHABI the personality routine is responsible for actually
|
||||||
|
// unwinding a single stack frame before returning (ARM EHABI Sec. 6.1).
|
||||||
|
unsafe fn continue_unwind(exception_object: *mut uw::_Unwind_Exception,
|
||||||
|
context: *mut uw::_Unwind_Context)
|
||||||
|
-> uw::_Unwind_Reason_Code {
|
||||||
|
if __gnu_unwind_frame(exception_object, context) == uw::_URC_NO_REASON {
|
||||||
|
uw::_URC_CONTINUE_UNWIND
|
||||||
|
} else {
|
||||||
|
uw::_URC_FAILURE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// defined in libgcc
|
||||||
|
extern "C" {
|
||||||
|
fn __gnu_unwind_frame(exception_object: *mut uw::_Unwind_Exception,
|
||||||
|
context: *mut uw::_Unwind_Context)
|
||||||
|
-> uw::_Unwind_Reason_Code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
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.
|
||||||
|
debug!("Trying to raise exception");
|
||||||
|
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);
|
||||||
|
debug!("Result: {:?}", result);
|
||||||
|
|
||||||
|
INFLIGHT.backtrace_size = 0;
|
||||||
|
unimplemented!("top level exception handling");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe extern fn reraise() -> ! {
|
||||||
|
use cslice::AsCSlice;
|
||||||
|
|
||||||
|
debug!("Re-raise");
|
||||||
|
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]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@ use libcortex_a9::{cache::dcci_slice, mutex::Mutex, sync_channel::{self, sync_ch
|
||||||
use libsupport_zynq::boot::Core1;
|
use libsupport_zynq::boot::Core1;
|
||||||
|
|
||||||
use dyld;
|
use dyld;
|
||||||
|
use unwind;
|
||||||
|
use crate::eh_artiq;
|
||||||
use crate::rpc;
|
use crate::rpc;
|
||||||
use crate::rtio;
|
use crate::rtio;
|
||||||
|
|
||||||
|
@ -70,7 +72,7 @@ fn rpc_send_common(is_async: bool, service: u32, tag: &CSlice<u8>, data: *const
|
||||||
let core1_tx: &mut sync_channel::Sender<Message> = unsafe { mem::transmute(KERNEL_CHANNEL_1TO0) };
|
let core1_tx: &mut sync_channel::Sender<Message> = unsafe { mem::transmute(KERNEL_CHANNEL_1TO0) };
|
||||||
let mut buffer = Vec::<u8>::new();
|
let mut buffer = Vec::<u8>::new();
|
||||||
rpc::send_args(&mut buffer, service, tag.as_ref(), data).expect("RPC encoding failed");
|
rpc::send_args(&mut buffer, service, tag.as_ref(), data).expect("RPC encoding failed");
|
||||||
core1_tx.send(Message::RpcSend { is_async: is_async, data: Arc::new(buffer) });
|
core1_tx.send(Message::RpcSend { is_async, data: Arc::new(buffer) });
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn rpc_send(service: u32, tag: &CSlice<u8>, data: *const *const ()) {
|
extern fn rpc_send(service: u32, tag: &CSlice<u8>, data: *const *const ()) {
|
||||||
|
@ -132,10 +134,6 @@ extern fn rpc_recv(slot: *mut ()) -> usize {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn exception_unimplemented() {
|
|
||||||
unimplemented!();
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! api {
|
macro_rules! api {
|
||||||
($i:ident) => ({
|
($i:ident) => ({
|
||||||
extern { static $i: u8; }
|
extern { static $i: u8; }
|
||||||
|
@ -250,12 +248,13 @@ fn resolve(required: &[u8]) -> Option<u32> {
|
||||||
api!(__aeabi_memclr8),
|
api!(__aeabi_memclr8),
|
||||||
api!(__aeabi_memclr4),
|
api!(__aeabi_memclr4),
|
||||||
api!(__aeabi_memclr),
|
api!(__aeabi_memclr),
|
||||||
|
// libc
|
||||||
|
api!(memcmp, extern { fn memcmp(a: *const u8, b: *mut u8, size: usize); }),
|
||||||
// exceptions
|
// exceptions
|
||||||
api!(_Unwind_Resume = exception_unimplemented),
|
api!(_Unwind_Resume = unwind::_Unwind_Resume),
|
||||||
api!(__artiq_personality = exception_unimplemented),
|
api!(__artiq_personality = eh_artiq::artiq_personality),
|
||||||
api!(__artiq_raise = exception_unimplemented),
|
api!(__artiq_raise = eh_artiq::raise),
|
||||||
api!(__artiq_reraise = exception_unimplemented),
|
api!(__artiq_reraise = eh_artiq::reraise),
|
||||||
|
|
||||||
];
|
];
|
||||||
api.iter()
|
api.iter()
|
||||||
|
|
|
@ -2,13 +2,15 @@
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![recursion_limit="1024"] // for futures_util::select!
|
#![recursion_limit="1024"] // for futures_util::select!
|
||||||
#![feature(llvm_asm)]
|
#![feature(llvm_asm)]
|
||||||
|
#![feature(unwind_attributes)]
|
||||||
|
#![feature(panic_info_message)]
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use core::{cmp, str};
|
use core::{cmp, str};
|
||||||
use log::{info, error};
|
use log::{info, error};
|
||||||
|
|
||||||
use libboard_zynq::{timer::GlobalTimer, logger, devc};
|
use libboard_zynq::{timer::GlobalTimer, logger, devc, stdio};
|
||||||
use libsupport_zynq::ram;
|
use libsupport_zynq::ram;
|
||||||
|
|
||||||
mod sd_reader;
|
mod sd_reader;
|
||||||
|
@ -23,6 +25,8 @@ mod rtio;
|
||||||
mod kernel;
|
mod kernel;
|
||||||
mod moninj;
|
mod moninj;
|
||||||
mod load_pl;
|
mod load_pl;
|
||||||
|
mod eh_artiq;
|
||||||
|
mod panic;
|
||||||
|
|
||||||
fn identifier_read(buf: &mut [u8]) -> &str {
|
fn identifier_read(buf: &mut [u8]) -> &str {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -37,6 +41,12 @@ fn identifier_read(buf: &mut [u8]) -> &str {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn _putchar(byte: u8) {
|
||||||
|
let mut uart = stdio::get_uart();
|
||||||
|
uart.write_byte(byte);
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn main_core0() {
|
pub fn main_core0() {
|
||||||
let timer = GlobalTimer::start();
|
let timer = GlobalTimer::start();
|
||||||
|
@ -70,6 +80,7 @@ pub fn main_core0() {
|
||||||
// what we want (e.g. gateware configured via JTAG before PS
|
// what we want (e.g. gateware configured via JTAG before PS
|
||||||
// startup, or by FSBL).
|
// startup, or by FSBL).
|
||||||
} else {
|
} else {
|
||||||
|
// panic!("gateware not loaded");
|
||||||
// Load from SD card
|
// Load from SD card
|
||||||
match load_pl::load_bitstream_from_sd() {
|
match load_pl::load_bitstream_from_sd() {
|
||||||
Ok(_) => info!("Bitstream loaded successfully!"),
|
Ok(_) => info!("Bitstream loaded successfully!"),
|
||||||
|
@ -82,5 +93,7 @@ pub fn main_core0() {
|
||||||
pl::csr::rtio_core::reset_phy_write(1);
|
pl::csr::rtio_core::reset_phy_write(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
info!("Starting communication");
|
||||||
|
|
||||||
comms::main(timer);
|
comms::main(timer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
use unwind::backtrace;
|
||||||
|
use libboard_zynq::{slcr, print, println};
|
||||||
|
|
||||||
|
static mut PANICKED: bool = false;
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||||
|
print!("panic at ");
|
||||||
|
if let Some(location) = info.location() {
|
||||||
|
print!("{}:{}:{}", location.file(), location.line(), location.column());
|
||||||
|
} else {
|
||||||
|
print!("unknown location");
|
||||||
|
}
|
||||||
|
if let Some(message) = info.message() {
|
||||||
|
println!(": {}", message);
|
||||||
|
} else {
|
||||||
|
println!("");
|
||||||
|
}
|
||||||
|
|
||||||
|
if unsafe { PANICKED } {
|
||||||
|
print!("Panic in panic!");
|
||||||
|
} else {
|
||||||
|
unsafe {
|
||||||
|
PANICKED = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read backtrace can trigger panic.
|
||||||
|
println!("Backtrace:");
|
||||||
|
let _ = backtrace(|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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
slcr::RegisterBlock::unlocked(|slcr| slcr.soft_reset());
|
||||||
|
loop {}
|
||||||
|
}
|
Loading…
Reference in New Issue