Exception handling working
parent
faaf9e6ca0
commit
d2e1a57616
|
@ -35,6 +35,12 @@ version = "1.3.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7bbb73db36c1246e9034e307d0fba23f9a2e251faa47ade70c1bd252220c8311"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
|
@ -76,6 +82,16 @@ version = "0.2.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7313c0d620d0cb4dbd9d019e461a4beb501071ff46ec0ab933efb4daa76d73e3"
|
||||
|
||||
[[package]]
|
||||
name = "dwarf"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"compiler_builtins",
|
||||
"libc",
|
||||
"unwind",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dyld"
|
||||
version = "0.1.0"
|
||||
|
@ -184,7 +200,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "libasync"
|
||||
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 = [
|
||||
"embedded-hal",
|
||||
"libcortex_a9",
|
||||
|
@ -196,7 +212,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "libboard_zynq"
|
||||
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 = [
|
||||
"bit_field",
|
||||
"embedded-hal",
|
||||
|
@ -209,10 +225,14 @@ dependencies = [
|
|||
"volatile-register",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "libcortex_a9"
|
||||
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 = [
|
||||
"bit_field",
|
||||
"libregister",
|
||||
|
@ -221,7 +241,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "libregister"
|
||||
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 = [
|
||||
"bit_field",
|
||||
"vcell",
|
||||
|
@ -231,7 +251,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "libsupport_zynq"
|
||||
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 = [
|
||||
"compiler_builtins",
|
||||
"libboard_zynq",
|
||||
|
@ -364,16 +384,19 @@ dependencies = [
|
|||
"byteorder",
|
||||
"core_io",
|
||||
"cslice",
|
||||
"dwarf",
|
||||
"dyld",
|
||||
"fatfs",
|
||||
"futures",
|
||||
"libasync",
|
||||
"libboard_zynq",
|
||||
"libc",
|
||||
"libcortex_a9",
|
||||
"libsupport_zynq",
|
||||
"log",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"unwind",
|
||||
"void",
|
||||
]
|
||||
|
||||
|
@ -416,6 +439,16 @@ version = "0.2.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
||||
|
||||
[[package]]
|
||||
name = "unwind"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"compiler_builtins",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vcell"
|
||||
version = "0.1.2"
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
[workspace]
|
||||
members = [
|
||||
"libc",
|
||||
"libdyld",
|
||||
"libcoreio",
|
||||
"libdwarf",
|
||||
"libunwind",
|
||||
"runtime",
|
||||
"szl"
|
||||
]
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
"max-atomic-width": 32,
|
||||
"os": "none",
|
||||
"panic-strategy": "abort",
|
||||
"requires-uwtable": true,
|
||||
"force-unwind-tables": "yes",
|
||||
"relocation-model": "static",
|
||||
"target-c-int-width": "32",
|
||||
"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 log;
|
||||
|
||||
use core::{ops::Range, convert, fmt, str};
|
||||
use core::{convert, fmt, str};
|
||||
use alloc::string::String;
|
||||
use log::{debug, trace};
|
||||
use elf::*;
|
||||
|
@ -57,10 +57,43 @@ fn elf_hash(name: &[u8]) -> u32 {
|
|||
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 image: Image,
|
||||
dyn_section: DynamicSection,
|
||||
exidx: Range<usize>,
|
||||
}
|
||||
|
||||
impl Library {
|
||||
|
@ -130,10 +163,6 @@ impl Library {
|
|||
Ok(self.strtab().get(offset..offset + size)
|
||||
.ok_or("cannot read symbol name")?)
|
||||
}
|
||||
|
||||
pub fn exidx(&self) -> &[usize] {
|
||||
self.image.get_ref_slice_unchecked(&self.exidx)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load(
|
||||
|
@ -169,7 +198,6 @@ pub fn load(
|
|||
.map_err(|_| "cannot allocate target image")?;
|
||||
debug!("ELF target: {} bytes, align to {:X}, allocated at {:08X}", image_size, image_align, image.ptr() as usize);
|
||||
|
||||
let mut exidx = None;
|
||||
// LOAD
|
||||
for phdr in file.program_headers() {
|
||||
let phdr = phdr.ok_or("cannot read program header")?;
|
||||
|
@ -188,8 +216,13 @@ pub fn load(
|
|||
dst.copy_from_slice(src);
|
||||
}
|
||||
PT_ARM_EXIDX => {
|
||||
exidx = Some(phdr.p_vaddr as usize..
|
||||
(phdr.p_vaddr + phdr.p_filesz) as usize);
|
||||
let range = image.get(phdr.p_vaddr 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());
|
||||
let lib = Library {
|
||||
image,
|
||||
dyn_section,
|
||||
exidx: exidx.ok_or("missing EXIDX program header")?,
|
||||
dyn_section
|
||||
};
|
||||
|
||||
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"] }
|
||||
async-recursion = "0.3"
|
||||
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" }
|
||||
libasync = { git = "https://git.m-labs.hk/M-Labs/zc706.git" }
|
||||
dyld = { path = "../libdyld" }
|
||||
dwarf = { path = "../libdwarf" }
|
||||
unwind = { path = "../libunwind" }
|
||||
libc = { path = "../libc" }
|
||||
fatfs = { version = "0.3", features = ["core_io"], default-features = false }
|
||||
|
|
|
@ -17,12 +17,26 @@ MEMORY
|
|||
|
||||
SECTIONS
|
||||
{
|
||||
__text_start = .;
|
||||
.text :
|
||||
{
|
||||
KEEP(*(.text.exceptions));
|
||||
*(.text.boot);
|
||||
*(.text .text.*);
|
||||
} > SDRAM
|
||||
__text_end = .;
|
||||
|
||||
__exidx_start = .;
|
||||
.ARM.exidx :
|
||||
{
|
||||
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||
} > SDRAM
|
||||
__exidx_end = .;
|
||||
|
||||
.ARM.extab :
|
||||
{
|
||||
* (.ARM.extab*)
|
||||
} > SDRAM
|
||||
|
||||
.rodata : ALIGN(4)
|
||||
{
|
||||
|
@ -62,12 +76,4 @@ SECTIONS
|
|||
. += 0x10000;
|
||||
__stack0_start = .;
|
||||
} > 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 dyld;
|
||||
use unwind;
|
||||
use crate::eh_artiq;
|
||||
use crate::rpc;
|
||||
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 mut buffer = Vec::<u8>::new();
|
||||
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 ()) {
|
||||
|
@ -132,10 +134,6 @@ extern fn rpc_recv(slot: *mut ()) -> usize {
|
|||
}
|
||||
}
|
||||
|
||||
extern fn exception_unimplemented() {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
macro_rules! api {
|
||||
($i:ident) => ({
|
||||
extern { static $i: u8; }
|
||||
|
@ -250,12 +248,13 @@ fn resolve(required: &[u8]) -> Option<u32> {
|
|||
api!(__aeabi_memclr8),
|
||||
api!(__aeabi_memclr4),
|
||||
api!(__aeabi_memclr),
|
||||
|
||||
// libc
|
||||
api!(memcmp, extern { fn memcmp(a: *const u8, b: *mut u8, size: usize); }),
|
||||
// exceptions
|
||||
api!(_Unwind_Resume = exception_unimplemented),
|
||||
api!(__artiq_personality = exception_unimplemented),
|
||||
api!(__artiq_raise = exception_unimplemented),
|
||||
api!(__artiq_reraise = exception_unimplemented),
|
||||
api!(_Unwind_Resume = unwind::_Unwind_Resume),
|
||||
api!(__artiq_personality = eh_artiq::artiq_personality),
|
||||
api!(__artiq_raise = eh_artiq::raise),
|
||||
api!(__artiq_reraise = eh_artiq::reraise),
|
||||
|
||||
];
|
||||
api.iter()
|
||||
|
|
|
@ -2,13 +2,15 @@
|
|||
#![no_main]
|
||||
#![recursion_limit="1024"] // for futures_util::select!
|
||||
#![feature(llvm_asm)]
|
||||
#![feature(unwind_attributes)]
|
||||
#![feature(panic_info_message)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use core::{cmp, str};
|
||||
use log::{info, error};
|
||||
|
||||
use libboard_zynq::{timer::GlobalTimer, logger, devc};
|
||||
use libboard_zynq::{timer::GlobalTimer, logger, devc, stdio};
|
||||
use libsupport_zynq::ram;
|
||||
|
||||
mod sd_reader;
|
||||
|
@ -23,6 +25,8 @@ mod rtio;
|
|||
mod kernel;
|
||||
mod moninj;
|
||||
mod load_pl;
|
||||
mod eh_artiq;
|
||||
mod panic;
|
||||
|
||||
fn identifier_read(buf: &mut [u8]) -> &str {
|
||||
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]
|
||||
pub fn main_core0() {
|
||||
let timer = GlobalTimer::start();
|
||||
|
@ -70,6 +80,7 @@ pub fn main_core0() {
|
|||
// what we want (e.g. gateware configured via JTAG before PS
|
||||
// startup, or by FSBL).
|
||||
} else {
|
||||
// panic!("gateware not loaded");
|
||||
// Load from SD card
|
||||
match load_pl::load_bitstream_from_sd() {
|
||||
Ok(_) => info!("Bitstream loaded successfully!"),
|
||||
|
@ -82,5 +93,7 @@ pub fn main_core0() {
|
|||
pl::csr::rtio_core::reset_phy_write(1);
|
||||
}
|
||||
|
||||
info!("Starting communication");
|
||||
|
||||
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