#![allow(non_camel_case_types)]
pub use self::lucet_result::*;
pub use self::lucet_val::*;
use crate::alloc::Limits;
use crate::error::Error;
use crate::instance::signals::SignalBehavior;
use libc::{c_int, c_void};
use num_derive::FromPrimitive;
#[macro_export]
macro_rules! assert_nonnull {
( $name:ident ) => {
if $name.is_null() {
return lucet_error::InvalidArgument;
}
};
}
#[macro_export]
macro_rules! with_ffi_arcs {
( [ $name:ident : dyn $ty:ident ], $body:block ) => {{
assert_nonnull!($name);
let $name = Arc::from_raw($name as *const Arc<dyn $ty>);
let res = $body;
Arc::into_raw($name);
res
}};
( [ $name:ident : $ty:ty ], $body:block ) => {{
assert_nonnull!($name);
let $name = Arc::from_raw($name as *const $ty);
let res = $body;
Arc::into_raw($name);
res
}};
( [ $name:ident : dyn $ty:ident, $($tail:tt)* ], $body:block ) => {{
assert_nonnull!($name);
let $name = Arc::from_raw($name as *const Arc<dyn $ty>);
let rec = with_ffi_arcs!([$($tail)*], $body);
Arc::into_raw($name);
rec
}};
( [ $name:ident : $ty:ty, $($tail:tt)* ], $body:block ) => {{
assert_nonnull!($name);
let $name = Arc::from_raw($name as *const $ty);
let rec = with_ffi_arcs!([$($tail)*], $body);
Arc::into_raw($name);
rec
}};
}
#[repr(C)]
pub struct lucet_vmctx {
_unused: [u8; 0],
}
#[repr(C)]
#[derive(Clone, Copy, Debug, FromPrimitive)]
pub enum lucet_error {
Ok,
InvalidArgument,
RegionFull,
Module,
LimitsExceeded,
NoLinearMemory,
SymbolNotFound,
FuncNotFound,
RuntimeFault,
RuntimeTerminated,
Dl,
InstanceNotReturned,
InstanceNotYielded,
StartYielded,
Internal,
Unsupported,
}
impl From<Error> for lucet_error {
fn from(e: Error) -> lucet_error {
lucet_error::from(&e)
}
}
impl From<&Error> for lucet_error {
fn from(e: &Error) -> lucet_error {
match e {
Error::InvalidArgument(_) => lucet_error::InvalidArgument,
Error::RegionFull(_) => lucet_error::RegionFull,
Error::ModuleError(_) => lucet_error::Module,
Error::LimitsExceeded(_) => lucet_error::LimitsExceeded,
Error::NoLinearMemory(_) => lucet_error::NoLinearMemory,
Error::SymbolNotFound(_) => lucet_error::SymbolNotFound,
Error::FuncNotFound(_, _) => lucet_error::FuncNotFound,
Error::RuntimeFault(_) => lucet_error::RuntimeFault,
Error::RuntimeTerminated(_) => lucet_error::RuntimeTerminated,
Error::DlError(_) => lucet_error::Dl,
Error::InstanceNotReturned => lucet_error::InstanceNotReturned,
Error::InstanceNotYielded => lucet_error::InstanceNotYielded,
Error::StartYielded => lucet_error::StartYielded,
Error::InternalError(_) => lucet_error::Internal,
Error::Unsupported(_) => lucet_error::Unsupported,
}
}
}
#[repr(C)]
pub struct lucet_instance {
_unused: [u8; 0],
}
#[repr(C)]
pub struct lucet_region {
_unused: [u8; 0],
}
#[repr(C)]
pub struct lucet_dl_module {
_unused: [u8; 0],
}
#[derive(Clone, Debug)]
#[repr(C)]
pub struct lucet_alloc_limits {
pub heap_memory_size: u64,
pub heap_address_space_size: u64,
pub stack_size: u64,
pub globals_size: u64,
}
impl From<Limits> for lucet_alloc_limits {
fn from(limits: Limits) -> lucet_alloc_limits {
(&limits).into()
}
}
impl From<&Limits> for lucet_alloc_limits {
fn from(limits: &Limits) -> lucet_alloc_limits {
lucet_alloc_limits {
heap_memory_size: limits.heap_memory_size as u64,
heap_address_space_size: limits.heap_address_space_size as u64,
stack_size: limits.stack_size as u64,
globals_size: limits.globals_size as u64,
}
}
}
impl From<lucet_alloc_limits> for Limits {
fn from(limits: lucet_alloc_limits) -> Limits {
(&limits).into()
}
}
impl From<&lucet_alloc_limits> for Limits {
fn from(limits: &lucet_alloc_limits) -> Limits {
Limits {
heap_memory_size: limits.heap_memory_size as usize,
heap_address_space_size: limits.heap_address_space_size as usize,
stack_size: limits.stack_size as usize,
globals_size: limits.globals_size as usize,
}
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub enum lucet_signal_behavior {
Default,
Continue,
Terminate,
}
impl From<lucet_signal_behavior> for SignalBehavior {
fn from(sb: lucet_signal_behavior) -> SignalBehavior {
sb.into()
}
}
impl From<&lucet_signal_behavior> for SignalBehavior {
fn from(sb: &lucet_signal_behavior) -> SignalBehavior {
match sb {
lucet_signal_behavior::Default => SignalBehavior::Default,
lucet_signal_behavior::Continue => SignalBehavior::Continue,
lucet_signal_behavior::Terminate => SignalBehavior::Terminate,
}
}
}
pub type lucet_signal_handler = unsafe extern "C" fn(
inst: *mut lucet_instance,
trap: lucet_result::lucet_trapcode,
signum: c_int,
siginfo: *const libc::siginfo_t,
context: *const c_void,
) -> lucet_signal_behavior;
pub type lucet_fatal_handler = unsafe extern "C" fn(inst: *mut lucet_instance);
pub struct CTerminationDetails {
pub details: *mut c_void,
}
unsafe impl Send for CTerminationDetails {}
unsafe impl Sync for CTerminationDetails {}
pub struct CYieldedVal {
pub val: *mut c_void,
}
unsafe impl Send for CYieldedVal {}
unsafe impl Sync for CYieldedVal {}
pub mod lucet_result {
use super::lucet_error;
use crate::c_api::{lucet_val, CTerminationDetails, CYieldedVal};
use crate::error::Error;
use crate::instance::{RunResult, TerminationDetails};
use crate::module::{AddrDetails, TrapCode};
use libc::{c_uchar, c_void};
use num_derive::FromPrimitive;
use std::ffi::CString;
use std::ptr;
impl From<Result<RunResult, Error>> for lucet_result {
fn from(res: Result<RunResult, Error>) -> lucet_result {
match res {
Ok(RunResult::Returned(retval)) => lucet_result {
tag: lucet_result_tag::Returned,
val: lucet_result_val {
returned: retval.into(),
},
},
Ok(RunResult::Yielded(val)) => lucet_result {
tag: lucet_result_tag::Yielded,
val: lucet_result_val {
yielded: lucet_yielded {
val: val
.downcast_ref()
.map(|CYieldedVal { val }| *val)
.unwrap_or(ptr::null_mut()),
},
},
},
Err(Error::RuntimeFault(details)) => lucet_result {
tag: lucet_result_tag::Faulted,
val: lucet_result_val {
fault: lucet_runtime_faulted {
fatal: details.fatal,
trapcode: details.trapcode.into(),
rip_addr: details.rip_addr,
rip_addr_details: details.rip_addr_details.into(),
},
},
},
Err(Error::RuntimeTerminated(details)) => lucet_result {
tag: lucet_result_tag::Terminated,
val: lucet_result_val {
terminated: match details {
TerminationDetails::Signal => lucet_terminated {
reason: lucet_terminated_reason::Signal,
provided: ptr::null_mut(),
},
TerminationDetails::CtxNotFound => lucet_terminated {
reason: lucet_terminated_reason::CtxNotFound,
provided: ptr::null_mut(),
},
TerminationDetails::YieldTypeMismatch => lucet_terminated {
reason: lucet_terminated_reason::YieldTypeMismatch,
provided: ptr::null_mut(),
},
TerminationDetails::BorrowError(_) => lucet_terminated {
reason: lucet_terminated_reason::BorrowError,
provided: ptr::null_mut(),
},
TerminationDetails::Provided(p) => lucet_terminated {
reason: lucet_terminated_reason::Provided,
provided: p
.downcast_ref()
.map(|CTerminationDetails { details }| *details)
.unwrap_or(ptr::null_mut()),
},
},
},
},
Err(e) => lucet_result {
tag: lucet_result_tag::Errored,
val: lucet_result_val { errored: e.into() },
},
}
}
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct lucet_result {
pub tag: lucet_result_tag,
pub val: lucet_result_val,
}
#[repr(C)]
#[derive(Clone, Copy, Debug, FromPrimitive)]
pub enum lucet_result_tag {
Returned,
Yielded,
Faulted,
Terminated,
Errored,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub union lucet_result_val {
pub returned: lucet_val::lucet_untyped_retval,
pub yielded: lucet_yielded,
pub fault: lucet_runtime_faulted,
pub terminated: lucet_terminated,
pub errored: lucet_error,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct lucet_terminated {
pub reason: lucet_terminated_reason,
pub provided: *mut c_void,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub enum lucet_terminated_reason {
Signal,
CtxNotFound,
YieldTypeMismatch,
BorrowError,
Provided,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct lucet_yielded {
pub val: *mut c_void,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct lucet_runtime_faulted {
pub fatal: bool,
pub trapcode: lucet_trapcode,
pub rip_addr: libc::uintptr_t,
pub rip_addr_details: lucet_module_addr_details,
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub enum lucet_trapcode {
StackOverflow,
HeapOutOfBounds,
OutOfBounds,
IndirectCallToNull,
BadSignature,
IntegerOverflow,
IntegerDivByZero,
BadConversionToInteger,
Interrupt,
TableOutOfBounds,
Unreachable,
Unknown,
}
impl From<Option<TrapCode>> for lucet_trapcode {
fn from(ty: Option<TrapCode>) -> lucet_trapcode {
(&ty).into()
}
}
impl From<&Option<TrapCode>> for lucet_trapcode {
fn from(ty: &Option<TrapCode>) -> lucet_trapcode {
if let Some(ty) = ty {
match ty {
TrapCode::StackOverflow => lucet_trapcode::StackOverflow,
TrapCode::HeapOutOfBounds => lucet_trapcode::HeapOutOfBounds,
TrapCode::OutOfBounds => lucet_trapcode::OutOfBounds,
TrapCode::IndirectCallToNull => lucet_trapcode::IndirectCallToNull,
TrapCode::BadSignature => lucet_trapcode::BadSignature,
TrapCode::IntegerOverflow => lucet_trapcode::IntegerOverflow,
TrapCode::IntegerDivByZero => lucet_trapcode::IntegerDivByZero,
TrapCode::BadConversionToInteger => lucet_trapcode::BadConversionToInteger,
TrapCode::Interrupt => lucet_trapcode::Interrupt,
TrapCode::TableOutOfBounds => lucet_trapcode::TableOutOfBounds,
TrapCode::Unreachable => lucet_trapcode::Unreachable,
}
} else {
lucet_trapcode::Unknown
}
}
}
const ADDR_DETAILS_NAME_LEN: usize = 256;
#[repr(C)]
#[derive(Clone, Copy)]
pub struct lucet_module_addr_details {
pub module_code_resolvable: bool,
pub in_module_code: bool,
pub file_name: [c_uchar; ADDR_DETAILS_NAME_LEN],
pub sym_name: [c_uchar; ADDR_DETAILS_NAME_LEN],
}
impl Default for lucet_module_addr_details {
fn default() -> Self {
lucet_module_addr_details {
module_code_resolvable: false,
in_module_code: false,
file_name: [0; ADDR_DETAILS_NAME_LEN],
sym_name: [0; ADDR_DETAILS_NAME_LEN],
}
}
}
impl From<Option<AddrDetails>> for lucet_module_addr_details {
fn from(details: Option<AddrDetails>) -> Self {
fn trunc_c_str_bytes(s: &str) -> Vec<u8> {
let s = CString::new(s);
let mut bytes = s.ok().map(|s| s.into_bytes_with_nul()).unwrap_or(vec![0]);
bytes.truncate(ADDR_DETAILS_NAME_LEN);
*bytes.last_mut().unwrap() = 0;
bytes
}
let mut ret = details
.as_ref()
.map(|details| lucet_module_addr_details {
module_code_resolvable: true,
in_module_code: details.in_module_code,
file_name: [0; ADDR_DETAILS_NAME_LEN],
sym_name: [0; ADDR_DETAILS_NAME_LEN],
})
.unwrap_or_default();
let file_name_bytes = details
.as_ref()
.and_then(|details| details.file_name.as_ref().map(|s| trunc_c_str_bytes(s)))
.unwrap_or_else(|| vec![0]);
let sym_name_bytes = details
.and_then(|details| details.sym_name.as_ref().map(|s| trunc_c_str_bytes(s)))
.unwrap_or_else(|| vec![0]);
ret.file_name[0..file_name_bytes.len()].copy_from_slice(file_name_bytes.as_slice());
ret.sym_name[0..sym_name_bytes.len()].copy_from_slice(sym_name_bytes.as_slice());
ret
}
}
}
pub mod lucet_val {
use crate::val::{UntypedRetVal, UntypedRetValInternal, Val};
use libc::{c_char, c_void};
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub enum lucet_val_type {
C_Ptr,
GuestPtr,
U8,
U16,
U32,
U64,
I8,
I16,
I32,
I64,
USize,
ISize,
Bool,
F32,
F64,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub union lucet_val_inner_val {
as_c_ptr: *mut c_void,
as_u64: u64,
as_i64: i64,
as_f32: f32,
as_f64: f64,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct lucet_val {
ty: lucet_val_type,
inner_val: lucet_val_inner_val,
}
impl From<lucet_val> for Val {
fn from(val: lucet_val) -> Val {
(&val).into()
}
}
impl From<&lucet_val> for Val {
fn from(val: &lucet_val) -> Val {
match val.ty {
lucet_val_type::C_Ptr => Val::CPtr(unsafe { val.inner_val.as_u64 } as _),
lucet_val_type::GuestPtr => Val::GuestPtr(unsafe { val.inner_val.as_u64 } as _),
lucet_val_type::U8 => Val::U8(unsafe { val.inner_val.as_u64 } as _),
lucet_val_type::U16 => Val::U16(unsafe { val.inner_val.as_u64 } as _),
lucet_val_type::U32 => Val::U32(unsafe { val.inner_val.as_u64 } as _),
lucet_val_type::U64 => Val::U64(unsafe { val.inner_val.as_u64 } as _),
lucet_val_type::I8 => Val::I16(unsafe { val.inner_val.as_i64 } as _),
lucet_val_type::I16 => Val::I32(unsafe { val.inner_val.as_i64 } as _),
lucet_val_type::I32 => Val::I32(unsafe { val.inner_val.as_i64 } as _),
lucet_val_type::I64 => Val::I64(unsafe { val.inner_val.as_i64 } as _),
lucet_val_type::USize => Val::USize(unsafe { val.inner_val.as_u64 } as _),
lucet_val_type::ISize => Val::ISize(unsafe { val.inner_val.as_i64 } as _),
lucet_val_type::Bool => Val::Bool(unsafe { val.inner_val.as_u64 } != 0),
lucet_val_type::F32 => Val::F32(unsafe { val.inner_val.as_f32 } as _),
lucet_val_type::F64 => Val::F64(unsafe { val.inner_val.as_f64 } as _),
}
}
}
impl From<Val> for lucet_val {
fn from(val: Val) -> Self {
(&val).into()
}
}
impl From<&Val> for lucet_val {
fn from(val: &Val) -> Self {
match val {
Val::CPtr(a) => lucet_val {
ty: lucet_val_type::C_Ptr,
inner_val: lucet_val_inner_val { as_u64: *a as _ },
},
Val::GuestPtr(a) => lucet_val {
ty: lucet_val_type::GuestPtr,
inner_val: lucet_val_inner_val { as_u64: *a as _ },
},
Val::U8(a) => lucet_val {
ty: lucet_val_type::U8,
inner_val: lucet_val_inner_val { as_u64: *a as _ },
},
Val::U16(a) => lucet_val {
ty: lucet_val_type::U16,
inner_val: lucet_val_inner_val { as_u64: *a as _ },
},
Val::U32(a) => lucet_val {
ty: lucet_val_type::U32,
inner_val: lucet_val_inner_val { as_u64: *a as _ },
},
Val::U64(a) => lucet_val {
ty: lucet_val_type::U64,
inner_val: lucet_val_inner_val { as_u64: *a as _ },
},
Val::I8(a) => lucet_val {
ty: lucet_val_type::I8,
inner_val: lucet_val_inner_val { as_i64: *a as _ },
},
Val::I16(a) => lucet_val {
ty: lucet_val_type::I16,
inner_val: lucet_val_inner_val { as_i64: *a as _ },
},
Val::I32(a) => lucet_val {
ty: lucet_val_type::I32,
inner_val: lucet_val_inner_val { as_i64: *a as _ },
},
Val::I64(a) => lucet_val {
ty: lucet_val_type::I64,
inner_val: lucet_val_inner_val { as_i64: *a as _ },
},
Val::USize(a) => lucet_val {
ty: lucet_val_type::USize,
inner_val: lucet_val_inner_val { as_u64: *a as _ },
},
Val::ISize(a) => lucet_val {
ty: lucet_val_type::ISize,
inner_val: lucet_val_inner_val { as_i64: *a as _ },
},
Val::Bool(a) => lucet_val {
ty: lucet_val_type::Bool,
inner_val: lucet_val_inner_val { as_u64: *a as _ },
},
Val::F32(a) => lucet_val {
ty: lucet_val_type::F32,
inner_val: lucet_val_inner_val { as_f32: *a as _ },
},
Val::F64(a) => lucet_val {
ty: lucet_val_type::F64,
inner_val: lucet_val_inner_val { as_f64: *a as _ },
},
}
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct lucet_untyped_retval {
pub fp: [c_char; 16],
pub gp: [c_char; 8],
}
#[repr(C)]
#[derive(Clone, Copy)]
pub union lucet_retval_gp {
pub as_untyped: [c_char; 8],
pub as_c_ptr: *mut c_void,
pub as_u64: u64,
pub as_i64: i64,
}
impl From<UntypedRetVal> for lucet_untyped_retval {
fn from(retval: UntypedRetVal) -> lucet_untyped_retval {
let mut v = lucet_untyped_retval {
fp: [0; 16],
gp: [0; 8],
};
unsafe {
core::arch::x86_64::_mm_storeu_ps(
v.fp.as_mut().as_mut_ptr() as *mut f32,
retval.fp(),
);
*(v.gp.as_mut().as_mut_ptr() as *mut u64) = retval.gp();
}
v
}
}
}