commit
e139aa0ae9
46 changed files with 7880 additions and 0 deletions
@ -0,0 +1,10 @@
|
||||
gateware/build |
||||
misoc_* |
||||
*.o |
||||
*.a |
||||
*.d |
||||
*.elf |
||||
*.bin |
||||
*.lock |
||||
*.vcd |
||||
__pycache__ |
@ -0,0 +1,70 @@
|
||||
from artiq.experiment import * |
||||
import numpy as np |
||||
|
||||
class Benchmark(EnvExperiment): |
||||
def build(self): |
||||
self.setattr_device("core") |
||||
self.dds = self.get_device("urukul0_ch0") |
||||
|
||||
@kernel |
||||
def bisect_underflow(self, f, t_max_mu=1000, t_min_mu=0): |
||||
t = 0 |
||||
while (t_max_mu-t_min_mu) > 2: |
||||
t = np.int64( (t_max_mu+t_min_mu)/2 ) |
||||
print(np.int32(t_min_mu), np.int32(t_max_mu)) |
||||
try: |
||||
f(t) |
||||
except RTIOUnderflow: |
||||
print("Underflow") |
||||
if t == t_max_mu: |
||||
raise ValueError("Upper bound underflowed") |
||||
t_min_mu = t |
||||
else: |
||||
t_max_mu = t |
||||
return t |
||||
|
||||
@kernel |
||||
def dds_update_rate(self): |
||||
t=0 |
||||
def f(t): |
||||
self.core.reset() |
||||
for i in range(1000): |
||||
with parallel: |
||||
delay_mu(t) |
||||
self.dds.set(80*MHz, amplitude=0.1, phase=0.5) |
||||
t = self.bisect_underflow(lambda t: f(t), t_max_mu=50000) |
||||
print("Sustained DDS update time: ", np.int32(t), "mu") |
||||
|
||||
@kernel |
||||
def dds_setmu_update_rate(self): |
||||
t=0 |
||||
|
||||
def f(t): |
||||
f_mu = self.dds.frequency_to_ftw(80*MHz) |
||||
amp_mu = self.dds.amplitude_to_asf(0.1) |
||||
phase_mu = self.dds.turns_to_pow(0.5) |
||||
self.core.reset() |
||||
for i in range(1000): |
||||
with parallel: |
||||
delay_mu(t) |
||||
self.dds.set_mu(f_mu, asf=amp_mu, pow=phase_mu) |
||||
t = self.bisect_underflow(lambda t: f(t), t_max_mu=50000) |
||||
print("Sustained DDS set_mu update time: ", np.int32(t), "mu") |
||||
|
||||
@kernel |
||||
def measure_dds_timeline_advance(self): |
||||
self.core.break_realtime() |
||||
t0 = now_mu() |
||||
self.dds.set(80*MHz, amplitude=0.1, phase=0.5) |
||||
dt = now_mu()-t0 |
||||
core_log("DDS timeline advance:", np.int32(dt), "mu") |
||||
|
||||
@kernel |
||||
def run(self): |
||||
self.core.reset() |
||||
self.dds.cpld.init(blind=True) |
||||
self.dds.init(blind=True) |
||||
|
||||
# self.measure_dds_timeline_advance() |
||||
self.dds_update_rate() |
||||
# self.dds_setmu_update_rate() |
@ -0,0 +1,147 @@
|
||||
device_db = { |
||||
"core": { |
||||
"type": "local", |
||||
"module": "artiq.coredevice.core", |
||||
"class": "Core", |
||||
"arguments": {"host": "lalala", "ref_period": 1/(125e6), "ref_multiplier": 1} |
||||
}, |
||||
|
||||
"ttl0": { |
||||
"type": "local", |
||||
"module": "artiq.coredevice.ttl", |
||||
"class": "TTLInOut", |
||||
"arguments": {"channel": 0}, |
||||
}, |
||||
|
||||
|
||||
|
||||
"spi_urukul0": { |
||||
"type": "local", |
||||
"module": "artiq.coredevice.spi2", |
||||
"class": "SPIMaster", |
||||
"arguments": {"channel": 12} |
||||
}, |
||||
"ttl_urukul0_io_update": { |
||||
"type": "local", |
||||
"module": "artiq.coredevice.ttl", |
||||
"class": "TTLOut", |
||||
"arguments": {"channel": 13} |
||||
}, |
||||
"urukul0_cpld": { |
||||
"type": "local", |
||||
"module": "artiq.coredevice.urukul", |
||||
"class": "CPLD", |
||||
"arguments": { |
||||
"spi_device": "spi_urukul0", |
||||
"io_update_device": "ttl_urukul0_io_update", |
||||
"refclk": 125e6, |
||||
"clk_sel": 1 |
||||
} |
||||
}, |
||||
"urukul0_ch0": { |
||||
"type": "local", |
||||
"module": "artiq.coredevice.ad9910", |
||||
"class": "AD9910", |
||||
"arguments": { |
||||
"pll_n": 32, |
||||
"chip_select": 4, |
||||
"cpld_device": "urukul0_cpld", |
||||
} |
||||
}, |
||||
"urukul0_ch1": { |
||||
"type": "local", |
||||
"module": "artiq.coredevice.ad9910", |
||||
"class": "AD9910", |
||||
"arguments": { |
||||
"pll_n": 32, |
||||
"chip_select": 5, |
||||
"cpld_device": "urukul0_cpld", |
||||
} |
||||
}, |
||||
"urukul0_ch2": { |
||||
"type": "local", |
||||
"module": "artiq.coredevice.ad9910", |
||||
"class": "AD9910", |
||||
"arguments": { |
||||
"pll_n": 32, |
||||
"chip_select": 6, |
||||
"cpld_device": "urukul0_cpld", |
||||
} |
||||
}, |
||||
"urukul0_ch3": { |
||||
"type": "local", |
||||
"module": "artiq.coredevice.ad9910", |
||||
"class": "AD9910", |
||||
"arguments": { |
||||
"pll_n": 32, |
||||
"chip_select": 7, |
||||
"cpld_device": "urukul0_cpld", |
||||
} |
||||
}, |
||||
|
||||
|
||||
|
||||
"spi_urukul1": { |
||||
"type": "local", |
||||
"module": "artiq.coredevice.spi2", |
||||
"class": "SPIMaster", |
||||
"arguments": {"channel": 17} |
||||
}, |
||||
"ttl_urukul1_io_update": { |
||||
"type": "local", |
||||
"module": "artiq.coredevice.ttl", |
||||
"class": "TTLOut", |
||||
"arguments": {"channel": 18} |
||||
}, |
||||
"urukul1_cpld": { |
||||
"type": "local", |
||||
"module": "artiq.coredevice.urukul", |
||||
"class": "CPLD", |
||||
"arguments": { |
||||
"spi_device": "spi_urukul1", |
||||
"io_update_device": "ttl_urukul1_io_update", |
||||
"refclk": 125e6, |
||||
"clk_sel": 1 |
||||
} |
||||
}, |
||||
"urukul1_ch0": { |
||||
"type": "local", |
||||
"module": "artiq.coredevice.ad9910", |
||||
"class": "AD9910", |
||||
"arguments": { |
||||
"pll_n": 32, |
||||
"chip_select": 4, |
||||
"cpld_device": "urukul1_cpld", |
||||
} |
||||
}, |
||||
"urukul1_ch1": { |
||||
"type": "local", |
||||
"module": "artiq.coredevice.ad9910", |
||||
"class": "AD9910", |
||||
"arguments": { |
||||
"pll_n": 32, |
||||
"chip_select": 5, |
||||
"cpld_device": "urukul1_cpld", |
||||
} |
||||
}, |
||||
"urukul1_ch2": { |
||||
"type": "local", |
||||
"module": "artiq.coredevice.ad9910", |
||||
"class": "AD9910", |
||||
"arguments": { |
||||
"pll_n": 32, |
||||
"chip_select": 6, |
||||
"cpld_device": "urukul1_cpld", |
||||
} |
||||
}, |
||||
"urukul1_ch3": { |
||||
"type": "local", |
||||
"module": "artiq.coredevice.ad9910", |
||||
"class": "AD9910", |
||||
"arguments": { |
||||
"pll_n": 32, |
||||
"chip_select": 7, |
||||
"cpld_device": "urukul1_cpld", |
||||
} |
||||
}, |
||||
} |
@ -0,0 +1,46 @@
|
||||
from artiq.experiment import * |
||||
import numpy as np |
||||
|
||||
class Mandelbrot(EnvExperiment): |
||||
def build(self): |
||||
self.setattr_device("core") |
||||
|
||||
def col(self, i): |
||||
sys.stdout.write(" .,-:;i+hHM$*#@ "[i]) |
||||
|
||||
def row(self): |
||||
print("") |
||||
|
||||
# based on: http://warp.povusers.org/MandScripts/python.html |
||||
@kernel |
||||
def run(self): |
||||
minX = -2.0 |
||||
maxX = 1.0 |
||||
width = 78 |
||||
height = 36 |
||||
aspectRatio = 2 |
||||
|
||||
yScale = (maxX-minX)*(height/width)*aspectRatio |
||||
|
||||
accum = 0. |
||||
|
||||
t0 = self.core.get_rtio_counter_mu() |
||||
|
||||
for y in range(height): |
||||
for x in range(width): |
||||
c_r = minX+x*(maxX-minX)/width |
||||
c_i = y*yScale/height-yScale/2 |
||||
z_r = c_r |
||||
z_i = c_i |
||||
i = 0 |
||||
for i in range(16): |
||||
if z_r*z_r + z_i*z_i > 4: |
||||
break |
||||
new_z_r = (z_r*z_r)-(z_i*z_i) + c_r |
||||
z_i = 2*z_r*z_i + c_i |
||||
z_r = new_z_r |
||||
accum += i |
||||
|
||||
dt = self.core.get_rtio_counter_mu() - t0 |
||||
core_log("Execution time:", np.int32(dt), "mu") |
||||
# Takes 666763336 mu on Kasli |
@ -0,0 +1,14 @@
|
||||
from artiq.experiment import * |
||||
|
||||
|
||||
class Minimal(EnvExperiment): |
||||
def build(self): |
||||
self.setattr_device("core") |
||||
|
||||
@kernel |
||||
def run(self): |
||||
core_log(" :: Hello from kernel") |
||||
# try: |
||||
raise ValueError |
||||
# except ValueError as e: |
||||
# core_log(" :: Caught exception.") |
@ -0,0 +1,93 @@
|
||||
from artiq.experiment import * |
||||
import numpy as np |
||||
|
||||
class TtlTests(EnvExperiment): |
||||
def build(self): |
||||
self.setattr_device("core") |
||||
self.ttlio = self.get_device("ttl0") |
||||
|
||||
@kernel |
||||
def bisect_underflow(self, f, t_max_mu=1000, t_min_mu=0): |
||||
t = 0 |
||||
while (t_max_mu-t_min_mu) > 1: |
||||
t = np.int64( (t_max_mu+t_min_mu)/2 ) |
||||
print(np.int32(t_min_mu), np.int32(t_max_mu)) |
||||
try: |
||||
f(t) |
||||
except RTIOUnderflow: |
||||
print("Underflow") |
||||
if t == t_max_mu: |
||||
raise ValueError("Upper bound underflowed") |
||||
t_min_mu = t |
||||
else: |
||||
t_max_mu = t |
||||
return t |
||||
|
||||
@kernel |
||||
def test_input_operation(self): |
||||
core_log("") |
||||
core_log("Test input operation ...") |
||||
self.core.reset() |
||||
self.ttlio.output() |
||||
delay(10*us) |
||||
with parallel: |
||||
self.ttlio.gate_rising(10*us) |
||||
with sequential: |
||||
delay(1*us) |
||||
t_out_mu = now_mu() |
||||
self.ttlio.pulse(1*us) |
||||
t_in_mu = self.ttlio.timestamp_mu() |
||||
dt = np.int32(t_in_mu-t_out_mu) |
||||
core_log("t_in-t_out:", dt, "mu") |
||||
|
||||
|
||||
@kernel |
||||
def event_response(self): |
||||
"""How soon after an input event can we reliably schedule an output event""" |
||||
core_log("") |
||||
core_log("Measuring minimum event response time") |
||||
t = 0 |
||||
def f(t_delay): |
||||
self.core.reset() |
||||
|
||||
self.ttlio.output() |
||||
delay(1*us) |
||||
for i in range(10): |
||||
# Make sure we have plenty of slack |
||||
delay(1000*us) |
||||
self.ttlio.off() |
||||
delay(1*us) |
||||
with parallel: |
||||
self.ttlio.gate_rising(4*us) |
||||
with sequential: |
||||
delay(100*ns) |
||||
self.ttlio.pulse(100*ns) |
||||
|
||||
t_input = self.ttlio.timestamp_mu() |
||||
at_mu(t_input+t_delay) |
||||
self.ttlio.pulse(10*us) |
||||
t = self.bisect_underflow(lambda t: f(t), t_max_mu=10000) |
||||
core_log("Event response time: ", np.int32(t), "mu") |
||||
|
||||
@kernel |
||||
def output_pulse_rate(self): |
||||
"""Sustained TTL output pulse rate""" |
||||
core_log("") |
||||
core_log("Measuring sustained output pulse rate") |
||||
t=0 |
||||
def f(t): |
||||
self.core.break_realtime() |
||||
for i in range(20000): |
||||
delay_mu(t) |
||||
self.ttlio.pulse_mu(t) |
||||
t = self.bisect_underflow(lambda t: f(t), t_max_mu=1000) |
||||
core_log("Sustained pulse rate: ", np.int32(2*t), "mu") |
||||
|
||||
|
||||
|
||||
@kernel |
||||
def run(self): |
||||
self.core.reset() |
||||
self.test_input_operation() |
||||
self.output_pulse_rate() |
||||
self.event_response() |
@ -0,0 +1,18 @@
|
||||
from artiq.experiment import * |
||||
|
||||
class WallTime(EnvExperiment): |
||||
def build(self): |
||||
self.setattr_device("core") |
||||
|
||||
@kernel |
||||
def run(self): |
||||
t0 = self.core.get_rtio_counter_mu() |
||||
i = 0 |
||||
while True: |
||||
t = self.core.get_rtio_counter_mu() |
||||
dt_s = (t-t0) |
||||
if dt_s < 1e9: |
||||
continue |
||||
t0 = t |
||||
core_log(i) |
||||
i += 1 |
@ -0,0 +1,7 @@
|
||||
[workspace] |
||||
members = ["runtime"] |
||||
|
||||
[profile.dev] |
||||
incremental = true |
||||
lto = false |
||||
opt-level = 2 |
@ -0,0 +1,14 @@
|
||||
[package] |
||||
name = "board_misoc" |
||||
version = "0.1.0" |
||||
authors = ["cjb <cjb>"] |
||||
|
||||
|
||||
|
||||
|
||||
[dependencies] |
||||
|
||||
[lib] |
||||
path="lib.rs" |
||||
name = "board_misoc" |
||||
|
@ -0,0 +1,56 @@
|
||||
#![no_std] |
||||
#![feature(asm)] |
||||
|
||||
include!(concat!(env!("BUILDINC_DIRECTORY"), "/generated/csr.rs")); |
||||
|
||||
pub mod uart; |
||||
#[macro_use] |
||||
pub mod uart_console; |
||||
|
||||
// Clean = expunge cache line with writeback
|
||||
pub fn clean_data_cache(base: usize, len: usize) { |
||||
const CACHE_SYNC_OFFSET: isize = 0x0730/4; // Cache Sync
|
||||
const CACHE_CLEAN_PA_OFFSET: isize = 0x7B0/4; |
||||
const L2CC_BASE: *mut u32 = 0xF8F02000 as *mut u32; |
||||
const CACHE_LINE_LENGTH: usize = 32; |
||||
let mut addr = base & !(CACHE_LINE_LENGTH-1);
|
||||
loop { |
||||
if addr > base+len {break} |
||||
unsafe { |
||||
write_volatile(L2CC_BASE.offset(CACHE_CLEAN_PA_OFFSET), addr as u32); |
||||
write_volatile(L2CC_BASE.offset(CACHE_SYNC_OFFSET), 0); |
||||
|
||||
// Clean data cache line by virtual address
|
||||
asm!("mcr p15, 0, $0, c7, c10, 1"::"r"(addr)) |
||||
} |
||||
addr += CACHE_LINE_LENGTH; |
||||
} |
||||
} |
||||
|
||||
|
||||
use core::ptr::write_volatile; |
||||
|
||||
// Invalidate = expunge cache line without writeback
|
||||
pub fn invalidate_data_cache(base: usize, len: usize) { |
||||
const CACHE_SYNC_OFFSET: isize = 0x0730/4; // Cache Sync
|
||||
const CACHE_INVLD_PA_OFFSET: isize = 0x0770/4; // Cache Invalid by PA
|
||||
const L2CC_BASE: *mut u32 = 0xF8F02000 as *mut u32; |
||||
const CACHE_LINE_LENGTH: usize = 32; |
||||
|
||||
let mut addr = base & !(CACHE_LINE_LENGTH-1);
|
||||
loop { |
||||
if addr > base+len {break} |
||||
|
||||
unsafe { |
||||
write_volatile(L2CC_BASE.offset(CACHE_INVLD_PA_OFFSET), addr as u32); |
||||
write_volatile(L2CC_BASE.offset(CACHE_SYNC_OFFSET), 0); |
||||
|
||||
// Invalidate data cache line by virtual address
|
||||
asm!("mcr p15, 0, $0, c7, c6, 1"::"r"(addr)) |
||||
} |
||||
addr += CACHE_LINE_LENGTH; |
||||
} |
||||
} |
||||
|
||||
|
||||
|
@ -0,0 +1,14 @@
|
||||
use core::ptr::{read_volatile, write_volatile}; |
||||
|
||||
|
||||
pub const UART_BASE: *mut u32 = 0xE0001000 as *mut u32; |
||||
// pub const UART_BASE: *mut u32 = 0x101000 as *mut u32;
|
||||
|
||||
|
||||
#[export_name="uart_write"] |
||||
pub extern fn write(c: u8) { |
||||
unsafe { |
||||
while read_volatile(UART_BASE.offset(0x2c/4)) & 0x10 != 0 {} |
||||
write_volatile(UART_BASE.offset(0x30/4), c as u32); |
||||
} |
||||
} |
@ -0,0 +1,30 @@
|
||||
use core::fmt; |
||||
|
||||
|
||||
pub struct Console; |
||||
|
||||
impl fmt::Write for Console { |
||||
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> { |
||||
use uart; |
||||
|
||||
for c in s.bytes() { |
||||
unsafe { uart::write(c) } |
||||
} |
||||
|
||||
Ok(()) |
||||
} |
||||
} |
||||
|
||||
#[macro_export] |
||||
macro_rules! print { |
||||
($($arg:tt)*) => ({ |
||||
use core::fmt::Write; |
||||
write!($crate::uart_console::Console, $($arg)*).unwrap() |
||||
}) |
||||
} |
||||
|
||||
#[macro_export] |
||||
macro_rules! println { |
||||
($fmt:expr) => (print!(concat!($fmt, "\n"))); |
||||
($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*)); |
||||
} |
@ -0,0 +1,8 @@
|
||||
[package] |
||||
authors = ["M-Labs"] |
||||
name = "dyld" |
||||
version = "0.0.0" |
||||
|
||||
[lib] |
||||
name = "dyld" |
||||
path = "lib.rs" |
@ -0,0 +1,339 @@
|
||||
#![no_std] |
||||
|
||||
use core::{mem, ptr, fmt, slice, str, convert}; |
||||
use elf::*; |
||||
|
||||
pub mod elf; |
||||
|
||||
fn read_unaligned<T: Copy>(data: &[u8], offset: usize) -> Result<T, ()> { |
||||
if data.len() < offset + mem::size_of::<T>() { |
||||
Err(()) |
||||
} else { |
||||
let ptr = data.as_ptr().wrapping_offset(offset as isize) as *const T; |
||||
Ok(unsafe { ptr::read_unaligned(ptr) }) |
||||
} |
||||
} |
||||
|
||||
fn get_ref<T: Copy>(data: &[u8], offset: usize) -> Result<&T, ()> { |
||||
if data.len() < offset + mem::size_of::<T>() { |
||||
Err(()) |
||||
} else if (data.as_ptr() as usize + offset) & (mem::align_of::<T>() - 1) != 0 { |
||||
Err(()) |
||||
} else { |
||||
let ptr = data.as_ptr().wrapping_offset(offset as isize) as *const T; |
||||
Ok(unsafe { &*ptr }) |
||||
} |
||||
} |
||||
|
||||
fn get_ref_slice<T: Copy>(data: &[u8], offset: usize, len: usize) -> Result<&[T], ()> { |
||||
if data.len() < offset + mem::size_of::<T>() * len { |
||||
Err(()) |
||||
} else if (data.as_ptr() as usize + offset) & (mem::align_of::<T>() - 1) != 0 { |
||||
Err(()) |
||||
} else { |
||||
let ptr = data.as_ptr().wrapping_offset(offset as isize) as *const T; |
||||
Ok(unsafe { slice::from_raw_parts(ptr, len) }) |
||||
} |
||||
} |
||||
|
||||
fn elf_hash(name: &[u8]) -> u32 { |
||||
let mut h: u32 = 0; |
||||
for c in name { |
||||
h = (h << 4) + *c as u32; |
||||
let g = h & 0xf0000000; |
||||
if g != 0 { |
||||
h ^= g >> 24; |
||||
h &= !g; |
||||
} |
||||
} |
||||
h |
||||
} |
||||
|
||||
#[derive(Debug)] |
||||
pub enum Error<'a> { |
||||
Parsing(&'static str), |
||||
Lookup(&'a [u8]) |
||||
} |
||||
|
||||
impl<'a> convert::From<&'static str> for Error<'a> { |
||||
fn from(desc: &'static str) -> Error<'a> { |
||||
Error::Parsing(desc) |
||||
} |
||||
} |
||||
|
||||
impl<'a> fmt::Display for Error<'a> { |
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
||||
match self { |
||||
&Error::Parsing(desc) => |
||||
write!(f, "parse error: {}", desc), |
||||
&Error::Lookup(sym) => |
||||
match str::from_utf8(sym) { |
||||
Ok(sym) => write!(f, "symbol lookup error: {}", sym), |
||||
Err(_) => write!(f, "symbol lookup error: {:?}", sym) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
pub struct Library<'a> { |
||||
image_off: Elf32_Addr, |
||||
image_sz: usize, |
||||
strtab: &'a [u8], |
||||
symtab: &'a [Elf32_Sym], |
||||
pltrel: &'a [Elf32_Rela], |
||||
hash_bucket: &'a [Elf32_Word], |
||||
hash_chain: &'a [Elf32_Word], |
||||
} |
||||
|
||||
impl<'a> Library<'a> { |
||||
pub fn lookup(&self, name: &[u8]) -> Option<Elf32_Word> { |
||||
let hash = elf_hash(name); |
||||
let mut index = self.hash_bucket[hash as usize % self.hash_bucket.len()] as usize; |
||||
|
||||
loop { |
||||
if index == STN_UNDEF { return None } |
||||
|
||||
let sym = &self.symtab[index]; |
||||
let sym_name_off = sym.st_name as usize; |
||||
match self.strtab.get(sym_name_off..sym_name_off + name.len()) { |
||||
Some(sym_name) if sym_name == name => { |
||||
if ELF32_ST_BIND(sym.st_info) & STB_GLOBAL == 0 { |
||||
return None |
||||
} |
||||
|
||||
match sym.st_shndx { |
||||
SHN_UNDEF => return None, |
||||
SHN_ABS => return Some(sym.st_value), |
||||
_ => return Some(self.image_off + sym.st_value) |
||||
} |
||||
} |
||||
_ => (), |
||||
} |
||||
|
||||
index = self.hash_chain[index] as usize; |
||||
} |
||||
} |
||||
|
||||
fn name_starting_at(&self, offset: usize) -> Result<&'a [u8], Error<'a>> { |
||||
let size = self.strtab.iter().skip(offset).position(|&x| x == 0) |
||||
.ok_or("symbol in symbol table not null-terminated")?; |
||||
Ok(self.strtab.get(offset..offset + size) |
||||
.ok_or("cannot read symbol name")?) |
||||
} |
||||
|
||||
fn update_rela(&self, rela: &Elf32_Rela, value: Elf32_Word) -> Result<(), Error<'a>> { |
||||
if rela.r_offset as usize + mem::size_of::<Elf32_Addr>() > self.image_sz { |
||||
return Err("relocation out of image bounds")? |
||||
} |
||||
|
||||
let ptr = (self.image_off + rela.r_offset) as *mut Elf32_Addr; |
||||
Ok(unsafe { *ptr = value }) |
||||
} |
||||
|
||||
// This is unsafe because it mutates global data (the PLT).
|
||||
pub unsafe fn rebind(&self, name: &[u8], addr: Elf32_Word) -> Result<(), Error<'a>> { |
||||
for rela in self.pltrel.iter() { |
||||
match ELF32_R_TYPE(rela.r_info) { |
||||
R_OR1K_32 | R_OR1K_GLOB_DAT | R_OR1K_JMP_SLOT => { |
||||
let sym = self.symtab.get(ELF32_R_SYM(rela.r_info) as usize) |
||||
.ok_or("symbol out of bounds of symbol table")?; |
||||
let sym_name = self.name_starting_at(sym.st_name as usize)?; |
||||
|
||||
if sym_name == name { |
||||
self.update_rela(rela, addr)? |
||||
} |
||||
} |
||||
|
||||
// No associated symbols for other relocation types.
|
||||
_ => () |
||||
} |
||||
} |
||||
Ok(()) |
||||
} |
||||
|
||||
fn resolve_rela(&self, rela: &Elf32_Rela, resolve: &Fn(&[u8]) -> Option<Elf32_Word>) |
||||
-> Result<(), Error<'a>> { |
||||
let sym; |
||||
if ELF32_R_SYM(rela.r_info) == 0 { |
||||
sym = None; |
||||
} else { |
||||
sym = Some(self.symtab.get(ELF32_R_SYM(rela.r_info) as usize) |
||||
.ok_or("symbol out of bounds of symbol table")?) |
||||
} |
||||
|
||||
let value; |
||||
match ELF32_R_TYPE(rela.r_info) { |
||||
R_OR1K_NONE => |
||||
return Ok(()), |
||||
|
||||
R_OR1K_RELATIVE => |
||||
value = self.image_off + rela.r_addend as Elf32_Word, |
||||
|
||||
R_OR1K_32 | R_OR1K_GLOB_DAT | R_OR1K_JMP_SLOT => { |
||||
let sym = sym.ok_or("relocation requires an associated symbol")?; |
||||
let sym_name = self.name_starting_at(sym.st_name as usize)?; |
||||
|
||||
// First, try to resolve against itself.
|
||||
match self.lookup(sym_name) { |
||||
Some(addr) => value = addr, |
||||
None => { |
||||
// Second, call the user-provided function.
|
||||
match resolve(sym_name) { |
||||
Some(addr) => value = addr, |
||||
None => { |
||||
// We couldn't find it anywhere.
|
||||
return Err(Error::Lookup(sym_name)) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
_ => return Err("unsupported relocation type")? |
||||
} |
||||
|
||||
self.update_rela(rela, value) |
||||
} |
||||
|
||||
pub fn load(data: &[u8], image: &'a mut [u8], resolve: &Fn(&[u8]) -> Option<Elf32_Word>) |
||||
-> Result<Library<'a>, Error<'a>> { |
||||
#![allow(unused_assignments)] |
||||
|
||||
let ehdr = read_unaligned::<Elf32_Ehdr>(data, 0) |
||||
.map_err(|()| "cannot read ELF header")?; |
||||
|
||||
const IDENT: [u8; EI_NIDENT] = [ |
||||
ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, |
||||
ELFCLASS32, ELFDATA2MSB, EV_CURRENT, ELFOSABI_NONE, |
||||
/* ABI version */ 0, /* padding */ 0, 0, 0, 0, 0, 0, 0 |
||||
]; |
||||
|
||||
#[cfg(target_arch = "or1k")] |
||||
const ARCH: u16 = EM_OPENRISC; |
||||
#[cfg(not(target_arch = "or1k"))] |
||||
const ARCH: u16 = EM_NONE; |
||||
|
||||
if ehdr.e_ident != IDENT || ehdr.e_type != ET_DYN || ehdr.e_machine != ARCH { |
||||
return Err("not a shared library for current architecture")? |
||||
} |
||||
|
||||
let mut dyn_off = None; |
||||
for i in 0..ehdr.e_phnum { |
||||
let phdr_off = ehdr.e_phoff as usize + mem::size_of::<Elf32_Phdr>() * i as usize; |
||||
let phdr = read_unaligned::<Elf32_Phdr>(data, phdr_off) |
||||
.map_err(|()| "cannot read program header")?; |
||||
|
||||
match phdr.p_type { |
||||
PT_LOAD => { |
||||
if (phdr.p_vaddr + phdr.p_filesz) as usize > image.len() || |
||||
(phdr.p_offset + phdr.p_filesz) as usize > data.len() { |
||||
return Err("program header requests an out of bounds load")? |
||||
} |
||||
let dst = image.get_mut(phdr.p_vaddr as usize.. |
||||
(phdr.p_vaddr + phdr.p_filesz) as usize) |
||||
.ok_or("cannot write to program header destination")?; |
||||
let src = data.get(phdr.p_offset as usize.. |
||||
(phdr.p_offset + phdr.p_filesz) as usize) |
||||
.ok_or("cannot read from program header source")?; |
||||
dst.copy_from_slice(src); |
||||
} |
||||
|
||||
PT_DYNAMIC => |
||||
dyn_off = Some(phdr.p_vaddr), |
||||
|
||||
_ => () |
||||
} |
||||
} |
||||
|
||||
let (mut strtab_off, mut strtab_sz) = (0, 0); |
||||
let (mut symtab_off, mut symtab_sz) = (0, 0); |
||||
let (mut rela_off, mut rela_sz) = (0, 0); |
||||
let (mut pltrel_off, mut pltrel_sz) = (0, 0); |
||||
let (mut hash_off, mut hash_sz) = (0, 0); |
||||
let mut sym_ent = 0; |
||||
let mut rela_ent = 0; |
||||
let mut nbucket = 0; |
||||
let mut nchain = 0; |
||||
|
||||
let dyn_off = dyn_off.ok_or("cannot find a dynamic header")?; |
||||
for i in 0.. { |
||||
let dyn_off = dyn_off as usize + i * mem::size_of::<Elf32_Dyn>(); |
||||
let dyn = get_ref::<Elf32_Dyn>(image, dyn_off) |
||||
.map_err(|()| "cannot read dynamic header")?; |
||||
|
||||
let val = unsafe { dyn.d_un.d_val } as usize; |
||||
match dyn.d_tag { |
||||
DT_NULL => break, |
||||
DT_REL => return Err("relocations with implicit addend are not supported")?, |
||||
DT_STRTAB => strtab_off = val, |
||||
DT_STRSZ => strtab_sz = val, |
||||
DT_SYMTAB => symtab_off = val, |
||||
DT_SYMENT => sym_ent = val, |
||||
DT_RELA => rela_off = val, |
||||
DT_RELASZ => rela_sz = val / mem::size_of::<Elf32_Rela>(), |
||||
DT_RELAENT => rela_ent = val, |
||||
DT_JMPREL => pltrel_off = val, |
||||
DT_PLTRELSZ => pltrel_sz = val / mem::size_of::<Elf32_Rela>(), |
||||
DT_HASH => { |
||||
nbucket = *get_ref::<Elf32_Word>(image, val + 0) |
||||
.map_err(|()| "cannot read hash bucket count")? as usize; |
||||
nchain = *get_ref::<Elf32_Word>(image, val + 4) |
||||
.map_err(|()| "cannot read hash chain count")? as usize; |
||||
hash_off = val + 8; |
||||
hash_sz = nbucket + nchain; |
||||
} |
||||
_ => () |
||||
} |
||||
} |
||||
|
||||
if sym_ent != mem::size_of::<Elf32_Sym>() { |
||||
return Err("incorrect symbol entry size")? |
||||
} |
||||
if rela_ent != mem::size_of::<Elf32_Rela>() { |
||||
return Err("incorrect relocation entry size")? |
||||
} |
||||
|
||||
// These are the same--there are as many chains as buckets, and the chains only contain
|
||||
// the symbols that overflowed the bucket.
|
||||
symtab_sz = nchain; |
||||
|
||||
// Drop the mutability. See also the comment below.
|
||||
let image = &*image; |
||||
|
||||
let strtab = get_ref_slice::<u8>(image, strtab_off, strtab_sz) |
||||
.map_err(|()| "cannot read string table")?; |
||||
let symtab = get_ref_slice::<Elf32_Sym>(image, symtab_off, symtab_sz) |
||||
.map_err(|()| "cannot read symbol table")?; |
||||
let rela = get_ref_slice::<Elf32_Rela>(image, rela_off, rela_sz) |
||||
.map_err(|()| "cannot read rela entries")?; |
||||
let pltrel = get_ref_slice::<Elf32_Rela>(image, pltrel_off, pltrel_sz) |
||||
.map_err(|()| "cannot read pltrel entries")?; |
||||
let hash = get_ref_slice::<Elf32_Word>(image, hash_off, hash_sz) |
||||
.map_err(|()| "cannot read hash entries")?; |
||||
|
||||
let library = Library { |
||||
image_off: image.as_ptr() as Elf32_Word, |
||||
image_sz: image.len(), |
||||
strtab: strtab, |
||||
symtab: symtab, |
||||
pltrel: pltrel, |
||||
hash_bucket: &hash[..nbucket], |
||||
hash_chain: &hash[nbucket..nbucket + nchain], |
||||
}; |
||||
|
||||
// If a borrow exists anywhere, the borrowed memory cannot be mutated except
|
||||
// through that pointer or it's UB. However, we need to retain pointers
|
||||
// to the symbol tables and relocations, and at the same time mutate the code
|
||||
// to resolve the relocations.
|
||||
//
|
||||
// To avoid invoking UB, we drop the only pointer to the entire area (which is
|
||||
// unique since it's a &mut); we retain pointers to the various tables, but
|
||||
// we never write to the memory they refer to, so it's safe.
|
||||
mem::drop(image); |
||||
|
||||
for r in rela { library.resolve_rela(r, resolve)? } |
||||
for r in pltrel { library.resolve_rela(r, resolve)? } |
||||
|
||||
Ok(library) |
||||
} |
||||
} |
Binary file not shown.
@ -0,0 +1,20 @@
|
||||
[package] |
||||
name = "ksupport" |
||||
version = "0.1.0" |
||||
authors = ["cjb <cjb>"] |
||||
|
||||
|
||||
[build-dependencies] |
||||
cc = "1.0" |
||||
|
||||
[dependencies] |
||||
board_misoc = { path = "../libboard_misoc"} |
||||
cslice = { version = "0.3" } |
||||
unwind = { path = "../libunwind-rs" } |
||||
libc = { default-features = false } |
||||
volatile_cell = "1.0" |
||||
|
||||
[lib] |
||||
path="lib.rs" |
||||
name = "ksupport" |
||||
|
@ -0,0 +1,89 @@
|
||||
macro_rules! api { |
||||
($i:ident) => ({ |
||||
extern { static $i: u8; } |
||||
api!($i = &$i as *const _) |
||||
}); |
||||
($i:ident, $d:item) => ({ |
||||
$d |
||||
api!($i = $i) |
||||
}); |
||||
($i:ident = $e:expr) => { |
||||
(stringify!($i), unsafe { $e as *const () }) |
||||
} |
||||
} |
||||
|
||||
|
||||
#[allow(unused_unsafe)] |
||||
static mut API: &'static [(&'static str, *const ())] = &[ |
||||
api!(__divsi3), |
||||
api!(__modsi3), |
||||
api!(__ledf2), |
||||
api!(__gedf2), |
||||
api!(__unorddf2), |
||||
api!(__eqdf2), |
||||
api!(__ltdf2), |
||||
api!(__nedf2), |
||||
api!(__gtdf2), |
||||
api!(__addsf3), |
||||
api!(__subsf3), |
||||
api!(__mulsf3), |
||||
api!(__divsf3), |
||||
api!(__lshrdi3), |
||||
api!(__muldi3), |
||||
api!(__divdi3), |
||||
api!(__ashldi3), |
||||
api!(__ashrdi3), |
||||
api!(__udivmoddi4), |
||||
api!(__floatsisf), |
||||
api!(__floatunsisf), |
||||
api!(__fixsfsi), |
||||
api!(__fixunssfsi), |
||||
api!(__adddf3), |
||||
api!(__subdf3), |
||||
api!(__muldf3), |
||||
api!(__divdf3), |
||||
api!(__floatsidf), |
||||
api!(__floatunsidf), |
||||
api!(__floatdidf), |
||||
api!(__fixdfsi), |
||||
api!(__fixdfdi), |
||||
api!(__fixunsdfsi), |
||||
api!(__udivdi3), |
||||
api!(__umoddi3), |
||||
api!(__moddi3), |
||||
api!(__powidf2), |
||||
|
||||
/* libc */ |
||||
// api!(abort = ::abort),
|
||||
api!(memcmp, extern { fn memcmp(a: *const u8, b: *mut u8, size: usize); }), |
||||
|
||||
/* libm */ |
||||
api!(sqrt), |
||||
api!(round), |
||||
api!(floor), |
||||
|
||||
/* exceptions */ |
||||
api!(_Unwind_Resume = ::unwind::_Unwind_Resume), |
||||
api!(__artiq_personality = ::eh::personality), |
||||
api!(__artiq_raise = ::eh::raise), |
||||
api!(__artiq_reraise = ::eh::reraise), |
||||
|
||||
/* proxified syscalls */ |
||||
api!(core_log), |
||||
|
||||
api!(now = &::NOW as *const _), |
||||
|
||||
|
||||
/* direct syscalls */ |
||||
api!(rtio_init = ::rtio::init), |
||||
api!(rtio_get_counter = ::rtio::get_counter), |
||||
api!(rtio_log), |
||||
api!(rtio_output = ::rtio::output), |
||||
api!(rtio_output_wide = ::rtio::output_wide), |
||||
api!(rtio_input_timestamp = ::rtio::input_timestamp), |
||||
api!(rtio_input_data = ::rtio::input_data), |
||||
api!(rtio_input_data_timeout = ::rtio::input_data_timeout), |
||||
api!(rtio_input_timestamp_data = ::rtio::input_timestamp_data), |
||||
|
||||
]; |
||||
|
@ -0,0 +1,12 @@
|
||||
extern crate cc; |
||||
|
||||
|
||||
fn main() { |
||||
let glue_path = "glue.c"; |
||||
|
||||
println!("cargo:rerun-if-changed={}", glue_path); |
||||
|
||||
cc::Build::new() |
||||
.file(glue_path) |
||||
.compile("glue"); |
||||
} |
@ -0,0 +1,602 @@
|
||||
// Portions of the code in this file are derived from code by:
|
||||
//
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
#![allow(non_upper_case_globals, non_camel_case_types, dead_code)] |
||||
|
||||
use core::{ptr, mem}; |
||||
use cslice::CSlice; |
||||
use unwind as uw; |
||||
use libc::{c_int, c_void}; |
||||
|
||||
#[cfg(not(target_arch = "arm"))] |
||||
type _Unwind_Stop_Fn = extern "C" fn(version: c_int, |
||||
actions: uw::_Unwind_Action, |
||||
exception_class: uw::_Unwind_Exception_Class, |
||||
exception_object: *mut uw::_Unwind_Exception, |
||||
context: *mut uw::_Unwind_Context, |
||||
stop_parameter: *mut c_void) |
||||
-> uw::_Unwind_Reason_Code; |
||||
|
||||
#[cfg(target_arch = "arm")] |
||||
type _Unwind_Stop_Fn = extern "C" fn(state: uw::_Unwind_State, |
||||
exception_object: *mut uw::_Unwind_Exception, |
||||
context: *mut uw::_Unwind_Context) |
||||
-> uw::_Unwind_Reason_Code; |
||||
|
||||
extern { |
||||
fn _Unwind_ForcedUnwind(exception: *mut uw::_Unwind_Exception, |
||||
stop_fn: _Unwind_Stop_Fn, |
||||
stop_parameter: *mut c_void) -> uw::_Unwind_Reason_Code; |
||||
} |
||||
|
||||
const DW_EH_PE_omit: u8 = 0xFF; |
||||
const DW_EH_PE_absptr: u8 = 0x00; |
||||
|
||||
const DW_EH_PE_uleb128: u8 = 0x01; |
||||
const DW_EH_PE_udata2: u8 = 0x02; |
||||
const DW_EH_PE_udata4: u8 = 0x03; |
||||
const DW_EH_PE_udata8: u8 = 0x04; |
||||
const DW_EH_PE_sleb128: u8 = 0x09; |
||||
const DW_EH_PE_sdata2: u8 = 0x0A; |
||||
const DW_EH_PE_sdata4: u8 = 0x0B; |
||||
const DW_EH_PE_sdata8: u8 = 0x0C; |
||||
|
||||
const DW_EH_PE_pcrel: u8 = 0x10; |
||||
const DW_EH_PE_textrel: u8 = 0x20; |
||||
const DW_EH_PE_datarel: u8 = 0x30; |
||||
const DW_EH_PE_funcrel: u8 = 0x40; |
||||
const DW_EH_PE_aligned: u8 = 0x50; |
||||
|
||||
const DW_EH_PE_indirect: u8 = 0x80; |
||||
|
||||
#[derive(Clone)] |
||||
struct DwarfReader { |
||||
pub ptr: *const u8, |
||||
} |
||||
|
||||
impl DwarfReader { |
||||
fn new(ptr: *const u8) -> DwarfReader { |
||||
DwarfReader { ptr: ptr } |
||||
} |
||||
|
||||
// DWARF streams are packed, so e.g. a u32 would not necessarily be aligned
|
||||
// on a 4-byte boundary. This may cause problems on platforms with strict
|
||||
// alignment requirements. By wrapping data in a "packed" struct, we are
|
||||
// telling the backend to generate "misalignment-safe" code.
|
||||
unsafe fn read<T: Copy>(&mut self) -> T { |
||||
let result = ptr::read_unaligned(self.ptr as *const T); |
||||
self.ptr = self.ptr.offset(mem::size_of::<T>() as isize); |
||||
result |
||||
} |
||||
|
||||
// ULEB128 and SLEB128 encodings are defined in Section 7.6 - "Variable
|
||||
// Length Data".
|
||||
unsafe fn read_uleb128(&mut self) -> u64 { |
||||
let mut shift: usize = 0; |
||||
let mut result: u64 = 0; |
||||
let mut byte: u8; |
||||
loop { |
||||
byte = self.read::<u8>(); |
||||
result |= ((byte & 0x7F) as u64) << shift; |
||||
shift += 7; |
||||
if byte & 0x80 == 0 { |
||||
break; |
||||
} |
||||
} |
||||
result |
||||
} |
||||
|
||||
unsafe fn read_sleb128(&mut self) -> i64 { |
||||
let mut shift: usize = 0; |
||||
let mut result: u64 = 0; |
||||
let mut byte: u8; |
||||
loop { |
||||
byte = self.read::<u8>(); |
||||
result |= ((byte & 0x7F) as u64) << shift; |
||||
shift += 7; |
||||
if byte & 0x80 == 0 { |
||||
break; |
||||
} |
||||
} |
||||
// sign-extend
|
||||
if shift < 8 * mem::size_of::<u64>() && (byte & 0x40) != 0 { |
||||
result |= (!0 as u64) << shift; |
||||
} |
||||
result as i64 |
||||
} |
||||
|
||||
unsafe fn read_encoded_pointer(&mut self, encoding: u8) -> usize { |
||||
fn round_up(unrounded: usize, align: usize) -> usize { |
||||
debug_assert!(align.is_power_of_two()); |
||||
(unrounded + align - 1) & !(align - 1) |
||||
} |
||||
|
||||
debug_assert!(encoding != DW_EH_PE_omit); |
||||
|
||||
// DW_EH_PE_aligned implies it's an absolute pointer value
|
||||
if encoding == DW_EH_PE_aligned { |
||||
self.ptr = round_up(self.ptr as usize, mem::size_of::<usize>()) as *const u8; |
||||
return self.read::<usize>() |
||||
} |
||||
|
||||
let value_ptr = self.ptr; |
||||
let mut result = match encoding & 0x0F { |
||||
DW_EH_PE_absptr => self.read::<usize>(), |
||||
DW_EH_PE_uleb128 => self.read_uleb128() as usize, |
||||
DW_EH_PE_udata2 => self.read::<u16>() as usize, |
||||
DW_EH_PE_udata4 => self.read::<u32>() as usize, |
||||
DW_EH_PE_udata8 => self.read::<u64>() as usize, |
||||
DW_EH_PE_sleb128 => self.read_sleb128() as usize, |
||||
DW_EH_PE_sdata2 => self.read::<i16>() as usize, |
||||
DW_EH_PE_sdata4 => self.read::<i32>() as usize, |
||||
DW_EH_PE_sdata8 => self.read::<i64>() as usize, |
||||
_ => panic!(), |
||||
}; |
||||
|
||||
result += match encoding & 0x70 { |
||||
DW_EH_PE_absptr => 0, |
||||
// relative to address of the encoded value, despite the name
|
||||
DW_EH_PE_pcrel => value_ptr as usize, |
||||
// 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)(),
|
||||
_ => panic!(), |
||||
}; |
||||
|
||||
if encoding & DW_EH_PE_indirect != 0 { |
||||
result = *(result as *const usize); |
||||
} |
||||
|
||||
result |
||||
} |
||||
} |
||||
|
||||
fn encoding_size(encoding: u8) -> usize { |
||||
if encoding == DW_EH_PE_omit { |
||||
return 0 |
||||
} |
||||
|
||||
match encoding & 0x0F { |
||||
DW_EH_PE_absptr => mem::size_of::<usize>(), |
||||
DW_EH_PE_udata2 => 2, |
||||
DW_EH_PE_udata4 => 4, |
||||
DW_EH_PE_udata8 => 8, |
||||
DW_EH_PE_sdata2 => 2, |
||||
DW_EH_PE_sdata4 => 4, |
||||
DW_EH_PE_sdata8 => 8, |
||||
_ => panic!() |
||||
} |
||||
} |
||||
|
||||
pub enum EHAction { |
||||
None, |
||||
Cleanup(usize), |
||||
Catch(usize), |
||||
Terminate, |
||||
} |
||||
|
||||
unsafe fn find_eh_action(uw_exception: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context) -> EHAction { |
||||
|
||||
let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8; |
||||
let func_start = uw::_Unwind_GetRegionStart(context); |
||||
|
||||
if lsda.is_null() { |
||||
return EHAction::None |
||||
} |
||||
|
||||
let mut reader = DwarfReader::new(lsda); |
||||
|
||||
let start_encoding = reader.read::<u8>(); |
||||
// base address for landing pad offsets
|
||||
let lpad_base = if start_encoding != DW_EH_PE_omit { |
||||
reader.read_encoded_pointer(start_encoding) |
||||
} else { |
||||
func_start |
||||
}; |
||||
|
||||
let mut ttype_encoding = reader.read::<u8>(); |
||||
let ttype_encoding_size = encoding_size(ttype_encoding) as isize; |
||||
|
||||
let class_info; |
||||
if ttype_encoding != DW_EH_PE_omit { |
||||
// // FIXME: ARM-only override; refactor this into read_target2 or something.
|
||||
// // Alternatively, pass --target2=rel.
|
||||
// ttype_encoding = DW_EH_PE_pcrel | DW_EH_PE_indirect;
|
||||
|
||||
let class_info_offset = reader.read_uleb128(); |
||||
class_info = reader.ptr.offset(class_info_offset as isize); |
||||
} else { |
||||
class_info = ptr::null(); |
||||
} |
||||
assert!(!class_info.is_null()); |
||||
|
||||
let call_site_encoding = reader.read::<u8>(); |
||||
let call_site_table_length = reader.read_uleb128(); |
||||
let action_table = reader.ptr.offset(call_site_table_length as isize); |
||||
|
||||
let ip = uw::_Unwind_GetIP(context) - 1; |
||||
let exception_info = &mut *(uw_exception as *mut ExceptionInfo); |
||||
let exn_name = &exception_info.exception.unwrap().name; |
||||
|
||||
while reader.ptr < action_table { |
||||
let cs_start = reader.read_encoded_pointer(call_site_encoding); |
||||
let cs_len = reader.read_encoded_pointer(call_site_encoding); |
||||
let cs_lpad = reader.read_encoded_pointer(call_site_encoding); |
||||
let cs_action = reader.read_uleb128(); |
||||
|
||||
if ip < func_start + cs_start { |
||||
// Callsite table is sorted by cs_start, so if we've passed the ip, we
|
||||
// may stop searching.
|
||||
break
|
||||
} |
||||
if ip > func_start + cs_start + cs_len { |
||||
continue
|
||||
} |
||||
|
||||
if cs_lpad == 0 { |
||||
return EHAction::None |
||||
} |
||||
|
||||
let lpad = lpad_base + cs_lpad; |
||||
if cs_action == 0 { |
||||
return EHAction::Cleanup(lpad) |
||||
} |
||||
|
||||
let action_entry = action_table.offset((cs_action - 1) as isize); |
||||
let mut action_reader = DwarfReader::new(action_entry); |
||||
loop { |
||||
let type_info_offset = action_reader.read_sleb128() as isize; |
||||
let action_offset = action_reader.clone().read_sleb128() as isize; |
||||
assert!(type_info_offset >= 0); |
||||
|
||||
if type_info_offset > 0 { |
||||
let type_info_ptr_ptr = class_info.offset(-type_info_offset * ttype_encoding_size); |
||||
let type_info_ptr = DwarfReader::new(type_info_ptr_ptr) |
||||
.read_encoded_pointer(ttype_encoding); |
||||
let type_info = *(type_info_ptr as *const CSlice<u8>); |
||||
|
||||
if type_info.as_ref() == exn_name.as_ref() { |
||||
return EHAction::Catch(lpad) |